<<>> <> <> <> <> <> <> <> <> <> DIRECTORY Commander, -- for debug expandname BasicTime, Convert, FS, FSBackdoor, FSName, IO, PFS, PFSNames, RefText, Rope; FSOnPFSImpl: CEDAR PROGRAM IMPORTS Commander, Convert, IO, PFSNames, PFS, RefText, Rope EXPORTS FS, FSBackdoor, FSName ~ BEGIN ROPE: PRIVATE TYPE = Rope.ROPE; STREAM: PRIVATE TYPE = IO.STREAM; <> Error: PUBLIC ERROR [error: FS.ErrorDesc] ~ PFS.Error; Wrap: PROC [inner: PROC, wDir: ROPE] ~ { IF wDir = NIL THEN inner[] ELSE PFS.DoInWDir[PFS.PathFromRope[wDir], inner]; }; StreamOpen: PUBLIC PROC [fileName: ROPE, accessOptions: FS.AccessOptions ¬ $read, streamOptions: FS.StreamOptions ¬ FS.defaultStreamOptions, keep: CARDINAL ¬ 1, createByteCount: INT ¬ 2560, streamBufferParms: FS.StreamBufferParms ¬ FS.defaultStreamBufferParms, extendFileProc: FS.ExtendFileProc ¬ NIL, wantedCreatedTime: BasicTime.GMT ¬ BasicTime.nullGMT, remoteCheck: BOOL ¬ TRUE, wDir: ROPE ¬ NIL, checkFileType: BOOL ¬ FALSE, fileType: FS.FileType ¬ FS.tUnspecified ] RETURNS [st: STREAM] = { StreamOpenInner: PROC ~ { st ¬ PFS.StreamOpen[ fileName: PFS.PathFromRope[fileName], accessOptions: (SELECT accessOptions FROM read => read, write => write, create => create, append => append, ENDCASE => ERROR), wantedUniqueID: UIDFromGMT[wantedCreatedTime], checkFileType: checkFileType, fileType: [fileType], createOptions: [keep: keep], streamOptions: [includeFormatting: NOT streamOptions[tiogaRead], closeFSOpenFileOnClose: streamOptions[closeFSOpenFileOnClose]], streamBufferParms: [bytesPerBuffer: streamBufferParms.vmPagesPerBuffer*512, nBuffers: streamBufferParms.nBuffers] ]; }; Wrap[StreamOpenInner, wDir]; }; OpenFileFromStream: PUBLIC PROC [self: STREAM] RETURNS [FS.OpenFile] = { RETURN [WrapOpenFile[PFS.OpenFileFromStream[self]]] }; StreamFromOpenFile: PUBLIC PROC [openFile: FS.OpenFile, accessRights: FS.Lock ¬ $read, initialPosition: FS.InitialPosition ¬ $start, streamOptions: FS.StreamOptions ¬ FS.defaultStreamOptions, streamBufferParms: FS.StreamBufferParms ¬ FS.defaultStreamBufferParms, extendFileProc: FS.ExtendFileProc ¬ NIL ] RETURNS [stream: STREAM ¬ NIL] = { stream ¬ PFS.StreamFromOpenFile[ openFile: BreakOpenFile[openFile], accessOptions: SELECT TRUE FROM (accessRights = read) => read, ((accessRights = write) AND (initialPosition = start)) => write, ((accessRights = write) AND (initialPosition = end)) => append, ENDCASE => ERROR, -- Can't get here streamOptions: [includeFormatting: NOT streamOptions[tiogaRead], closeFSOpenFileOnClose: streamOptions[closeFSOpenFileOnClose]], streamBufferParms: [bytesPerBuffer: streamBufferParms.vmPagesPerBuffer*512, nBuffers: streamBufferParms.nBuffers] ]; }; Open: PUBLIC PROC [name: ROPE, lock: FS.Lock ¬ $read, wantedCreatedTime: BasicTime.GMT ¬ BasicTime.nullGMT, remoteCheck: BOOL ¬ TRUE, wDir: ROPE ¬ NIL, verifyNow: BOOL ¬ FALSE, checkFileType: BOOL ¬ FALSE, fileType: FS.FileType ¬ FS.tUnspecified ] RETURNS [file: FS.OpenFile ¬ FS.nullOpenFile] ~ { OpenInner: PROC ~ { file ¬ WrapOpenFile[PFS.Open[ name: PFS.PathFromRope[name], access: SELECT lock FROM read => read, write => write, ENDCASE => ERROR, wantedUniqueID: UIDFromGMT[wantedCreatedTime], checkFileType: checkFileType, fileType: [fileType] ]]; }; Wrap[OpenInner, wDir]; }; Create: PUBLIC PROC [name: ROPE, setPages: BOOL ¬ FALSE, pages: INT ¬ 0, setKeep: BOOL ¬ FALSE, keep: CARDINAL ¬ 1, wDir: ROPE ¬ NIL, fileType: FS.FileType ¬ FS.tUnspecified ] RETURNS [file: FS.OpenFile ¬ FS.nullOpenFile] ~ { CreateInner: PROC ~ { file ¬ WrapOpenFile[PFS.Open[ name: PFS.PathFromRope[name], access: create, fileType: [fileType], createOptions: [keep: IF setKeep THEN keep ELSE 0, fileType: [fileType]] ]]; }; Wrap[CreateInner, wDir]; }; BreakOpenFile: PROC [file: FS.OpenFile] RETURNS [PFS.OpenFile] = { WITH file SELECT FROM pfs: REF PFS.OpenFile => RETURN [pfs­]; ENDCASE => RETURN [NIL]; }; WrapOpenFile: PROC [file: PFS.OpenFile] RETURNS [FS.OpenFile] = { RETURN [IF file = NIL THEN FS.nullOpenFile ELSE [NEW[PFS.OpenFile ¬ file]]] }; GetInfo: PUBLIC PROC [file: FS.OpenFile] RETURNS [keep: CARDINAL ¬ 0, pages: INT ¬ 0, bytes: INT ¬ 0, created: BasicTime.GMT, lock: FS.Lock ¬ read, fileType: FS.FileType ¬ FS.tUnspecified] = { <> uniqueID: PFS.UniqueID; pfsFileType: PFS.FileType; [uniqueID: uniqueID, bytes: bytes, fileType: pfsFileType] ¬ PFS.GetInfo[BreakOpenFile[file]]; pages ¬ (bytes + 511)/512; created ¬ uniqueID.egmt.gmt; fileType ¬ [pfsFileType]; }; nameFormat: PFS.NameFormat ¬ brackets; RopeFromPath: PROC [path: PFS.PATH] RETURNS [ROPE] = INLINE { RETURN [IF path = NIL THEN NIL ELSE PFS.RopeFromPath[path, nameFormat]] }; GetName: PUBLIC PROC [file: FS.OpenFile] RETURNS [fullFName, attachedTo: ROPE] = { <> fullPath, attachedPath: PFS.PATH; [fullFName: fullPath, attachedTo: attachedPath] ¬ PFS.GetInfo[BreakOpenFile[file]]; fullFName ¬ RopeFromPath[fullPath]; attachedTo ¬ RopeFromPath[attachedPath]; }; SetByteCountAndCreatedTime: PUBLIC PROC [file: FS.OpenFile, bytes: INT ¬ -1, created: BasicTime.GMT ¬ BasicTime.nullGMT] ~ { PFS.SetByteCountAndUniqueID[BreakOpenFile[file], bytes, UIDFromGMT[created]]; }; FilePtr: TYPE = LONG POINTER TO INT; Copy: PUBLIC PROC [from, to: ROPE, setKeep: BOOL ¬ FALSE, keep: CARDINAL ¬ 1, wantedCreatedTime: BasicTime.GMT ¬ BasicTime.nullGMT, remoteCheck: BOOL ¬ TRUE, attach: BOOL ¬ FALSE, wDir: ROPE ¬ NIL ] RETURNS [toFName: ROPE] = { CopyInner: PROC ~ { Confirm: PFS.NameConfirmProc ~ { <> toFName ¬ RopeFromPath[fullName]; RETURN [TRUE]; }; IF attach THEN toFName ¬ RopeFromPath[ PFS.Attach[ attachment: PFS.PathFromRope[to], attachedFile: PFS.PathFromRope[from], wantedUniqueID: UIDFromGMT[wantedCreatedTime], remoteCheck: remoteCheck ! PFS.Error => { attach ¬ FALSE; CONTINUE } ] ]; IF NOT attach THEN { PFS.Copy[ from: PFS.PathFromRope[from], to: PFS.PathFromRope[to], wantedUniqueID: UIDFromGMT[wantedCreatedTime], confirmProc: Confirm ]; }; }; Wrap[CopyInner, wDir]; }; Rename: PUBLIC PROC [from, to: ROPE, setKeep: BOOL ¬ FALSE, keep: CARDINAL ¬ 1, wantedCreatedTime: BasicTime.GMT ¬ BasicTime.nullGMT, wDir: ROPE ¬ NIL ] = { RenameInner: PROC ~ { PFS.Rename[ from: PFS.PathFromRope[from], to: PFS.PathFromRope[to], wantedUniqueID: UIDFromGMT[wantedCreatedTime] ]; }; Wrap[RenameInner, wDir]; }; UIDFromGMT: PROC [gmt: BasicTime.GMT] RETURNS [PFS.UniqueID] ~ INLINE { RETURN [[egmt: [gmt: gmt, usecs: 0]]] }; Delete: PUBLIC PROC [name: ROPE, wantedCreatedTime: BasicTime.GMT ¬ BasicTime.nullGMT, wDir: ROPE ¬ NIL ] = { DeleteInner: PROC ~ { PFS.Delete[name: PFS.PathFromRope[name], wantedUniqueID: UIDFromGMT[wantedCreatedTime]]; }; Wrap[DeleteInner, wDir]; }; FileInfo: PUBLIC PROC [ name: ROPE, wantedCreatedTime: BasicTime.GMT ¬ BasicTime.nullGMT, remoteCheck: BOOL ¬ TRUE, wDir: ROPE ¬ NIL ] RETURNS [ fullFName, attachedTo: ROPE ¬ NIL, keep: CARDINAL ¬ 1, bytes: INT ¬ 0, created: BasicTime.GMT ¬ BasicTime.nullGMT, fileType: FS.FileType ¬ FS.tUnspecified ] = { <> <> FileInfoInner: PROC ~ { fullPath, attachedPath: PFS.PATH; uniqueID: PFS.UniqueID; pfsFileType: PFS.FileType; [fullFName: fullPath, attachedTo: attachedPath, uniqueID: uniqueID, bytes: bytes, fileType: pfsFileType] ¬ PFS.FileInfo[name: PFS.PathFromRope[name], wantedUniqueID: UIDFromGMT[wantedCreatedTime]]; fullFName ¬ RopeFromPath[fullPath]; attachedTo ¬ RopeFromPath[attachedPath]; created ¬ uniqueID.egmt.gmt; fileType ¬ [pfsFileType]; }; Wrap[FileInfoInner, wDir]; }; SetKeep: PUBLIC PROC [name: ROPE, keep: CARDINAL ¬ 1, wDir: ROPE ¬ NIL] = { SetKeepInner: PROC ~ { [] ¬ PFS.PathFromRope[name]; -- Syntax check }; Wrap[SetKeepInner, wDir]; }; BytesForPages: PUBLIC PROC [pages: INT] RETURNS [bytes: INT] = { RETURN [pages * 512] -- Ignore real page size }; PagesForBytes: PUBLIC PROC [bytes: INT] RETURNS [pages: INT] = { RETURN [(bytes+511)/512] }; GetWDir: PUBLIC PROC [wDir: ROPE ¬ NIL] RETURNS [ans: ROPE] ~ { GetWDirInner: PROC ~ {ans ¬ RopeFromPath[PFS.GetWDir[]]}; Wrap[GetWDirInner, wDir]; }; DIRPtr: TYPE = POINTER; DirEntPtr: TYPE = POINTER; EnumerateForNames: PUBLIC PROC [pattern: ROPE, proc: FS.NameProc, wDir: ROPE ¬ NIL] = { EachPath: PFS.NameProc ~ { <> continue ¬ proc[RopeFromPath[name]]; }; EnumerateForNamesInner: PROC ~ { PFS.EnumerateForNames[pattern: PFS.PathFromRope[pattern], proc: EachPath]; }; Wrap[EnumerateForNamesInner, wDir]; }; EnumerateForInfo: PUBLIC PROC [pattern: ROPE, proc: FS.InfoProc, wDir: ROPE ¬ NIL] = { EachInfo: PFS.InfoProc ~ { <> continue ¬ proc[fullFName~RopeFromPath[fullFName], attachedTo~RopeFromPath[attachedTo], created~uniqueID.egmt.gmt, bytes~bytes, keep~1, fileType~[fileType]]; }; EnumerateForInfoInner: PROC ~ { PFS.EnumerateForInfo[pattern: PFS.PathFromRope[pattern], proc: EachInfo]; }; Wrap[EnumerateForInfoInner, wDir]; }; Close: PUBLIC PROC [file: FS.OpenFile] = { PFS.Close[BreakOpenFile[file]] }; nullCP: FS.ComponentPositions = [server: nullPos, dir: nullPos, subDirs: nullPos, base: nullPos, ext: nullPos, ver: nullPos]; nullPos: FS.Position = [start: 0, length: 0]; ExpandName: PUBLIC PROC[name: ROPE, wDir: ROPE ¬ NIL] RETURNS [fullFName: ROPE ¬ NIL, cp: FS.ComponentPositions, dirOmitted: BOOL] = { path: PFS.PATH; scratch: REF TEXT ~ RefText.ObtainScratch[100]; text: REF TEXT ¬ scratch; GetPath: PROC ~ { path ¬ PFS.AbsoluteName[PFS.PathFromRope[name]]; }; lastVersion: PFSNames.Version ¬ [none]; Append: PROC [t: REF TEXT, p: PFS.PATH, i: INT] RETURNS [REF TEXT] ~ { comp: PFSNames.Component ~ PFSNames.Fetch[p, i]; RETURN[ RefText.AppendRope[t, comp.name.base, comp.name.start, comp.name.len] ]; }; isADirectory: BOOL; comps: NAT; Wrap[GetPath, wDir]; comps ¬ PFSNames.ComponentCount[path]; isADirectory ¬ PFSNames.IsADirectory[path]; dirOmitted ¬ FALSE; cp ¬ nullCP; <> <
> IF comps >= 2 THEN { text ¬ RefText.AppendChar[text, '[ ]; cp.server.start ¬ text.length; text ¬ Append[text, path, 1]; cp.server.length ¬ text.length-cp.server.start; text ¬ RefText.AppendChar[text, '] ]; cp.dir.start ¬ text.length; cp.subDirs.start ¬ text.length; }; <> SELECT TRUE FROM comps>3 OR comps=3 AND isADirectory => { text ¬ RefText.AppendChar[text, '< ]; cp.dir.start ¬ text.length; text ¬ Append[text, path, 2]; cp.dir.length ¬ text.length-cp.dir.start; text ¬ RefText.AppendChar[text, '> ]; cp.subDirs.start ¬ text.length; }; comps=3 AND NOT isADirectory => { cp.base.start ¬ text.length; text ¬ Append[text, path, 2]; cp.base.length ¬ text.length-cp.base.start; lastVersion ¬ path.ShortName[].version; dirOmitted ¬ TRUE; }; ENDCASE => dirOmitted ¬ TRUE; <> FOR i: NAT IN [3..comps) DO IF i> text ¬ Append[text, path, i]; cp.subDirs.length ¬ text.length-cp.subDirs.start; text ¬ RefText.AppendChar[text, '> ]; } ELSE { <> cp.base.start ¬ text.length; text ¬ Append[text, path, i]; cp.base.length ¬ text.length-cp.base.start; lastVersion ¬ path.ShortName[].version; }; ENDLOOP; <> IF lastVersion.versionKind # none THEN { text ¬ RefText.AppendChar[text, '! ]; cp.ver.start ¬ text.length; text ¬ SELECT lastVersion.versionKind FROM lowest => RefText.AppendChar[text, 'L ], highest => RefText.AppendChar[text, 'H ], all => RefText.AppendChar[text, '* ], numeric => Convert.AppendCard[text, lastVersion.version], ENDCASE => text; cp.ver.length ¬ text.length-cp.ver.start; }; <> FOR i: NAT DECREASING IN [cp.base.start..cp.base.start+cp.base.length) DO IF text[i] = '. THEN { cp.ext.start ¬ i+1; cp.ext.length ¬ cp.base.start+cp.base.length-(i+1); cp.base.length ¬ i-cp.base.start; EXIT; }; ENDLOOP; <> IF cp.base = nullPos THEN { cp.base.start ¬ text.length }; IF cp.ext = nullPos THEN {cp.ext.start ¬ cp.base.start+cp.base.length; IF cp.ext.start = CARDINAL[text.length-1] THEN cp.ext.start ¬ cp.ext.start+1}; IF cp.ver = nullPos THEN {cp.ver.start ¬ cp.ext.start+cp.ext.length; IF cp.ver.start = CARDINAL[text.length-1] THEN cp.ver.start ¬ cp.ver.start+1}; fullFName ¬ Rope.FromRefText[text]; RefText.ReleaseScratch[scratch]; }; <> EnumerateCacheForNames: PUBLIC PROC [proc: FSBackdoor.NameProc, volName, pattern: ROPE] = { -- This is pretty easy for Unix - it has no cache to enumerate. }; group: PACKED ARRAY FSBackdoor.ErrorCode OF FS.ErrorGroup = [ -- 4-- bug, bug, bug, bug, --14-- environment, environment, environment, environment, environment, environment, environment, environment, environment, environment, environment, environment, environment, environment, -- 2-- environment, environment, -- 9-- client, client, client, client, client, client, client, client, client, --12-- user, user, user, user, user, user, user, user, user, user, user, user ]; codeAtom: ARRAY FSBackdoor.ErrorCode OF ATOM = [ $ok, $inconsistent, $software, $badFP, $wentOffline, $hardware, $volumeFull, $fragmented, $noMoreVersions, $serverInaccessible, $connectionRejected, $connectionTimedOut, $badCredentials, $accessDenied, $quotaExceeded, $invalidPropertyPage, $badBTree, $outOfPropertySpace, $lockConflict, $fileBusy, $noCache, $wrongLock, $globalWriteLock, $zeroKeep, $badByteCount, $unknownPage, $invalidOpenFile, $notImplemented, $fileTypeMismatch, $nonCedarVolume, $unknownServer, $unknownVolume, $unknownFile, $unknownCreatedTime, $illegalName, $patternNotAllowed, $versionSpecified, $globalCreation, $badWorkingDir, $noKeeps, $cantUpdateTiogaFile ]; ProduceError: PUBLIC PROC [code: FSBackdoor.ErrorCode, explanation: ROPE] = { ERROR Error [ [group[code], codeAtom[code], explanation] ]; }; <> TranslateForRead: PUBLIC PROC [server: ROPE] RETURNS [LIST OF ROPE] = { RETURN [NIL] -- who uses this stuff? <> }; <<>> <> <> <> <<};>> <<>> <> BangVersionFile: PUBLIC PROC [file: ROPE, version: FSBackdoor.Version] RETURNS [ROPE] = { length: CARDINAL = Rope.Length[file]; bangIndex: CARDINAL = Rope.Index[file, IF length > 6 THEN length - 6 ELSE 0, "!"]; RETURN [ Rope.Replace [ file, bangIndex, length - bangIndex, VersionPartFromVersion[version] ] ]; }; VersionFromRope: PUBLIC PROC [r: ROPE] RETURNS [v: FSBackdoor.Version] = { IF Rope.IsEmpty[r] THEN v ¬ FSBackdoor.highestVersion ELSE [v, ] ¬ ParseVersion[r, 0, FALSE]; }; VersionPartFromVersion: PROC [version: FSBackdoor.Version] RETURNS [r: Rope.Text] = { t: REF TEXT; SELECT version FROM FSBackdoor.lowestVersion, FSBackdoor.highestVersion => r ¬ NIL; ENDCASE => TRUSTED { r ¬ Rope.NewText[6]; t ¬ LOOPHOLE[r]; t[0] ¬ '!; t.length ¬ 1; [] ¬ Convert.AppendInt[t, version]; }; }; ParseVersion: PROC [name: ROPE, index: CARDINAL, pattern: BOOL ¬ FALSE] RETURNS [value: FSBackdoor.Version, vI: FSName.VersionInfo] = { c: CHAR; lastIndex: CARDINAL = Rope.Length[name] - 1; IF lastIndex IN [index .. index+4] THEN SELECT c ¬ Rope.Fetch[name, index] FROM IN ['0 .. '9] => { num: LONG CARDINAL ¬ 0; DO num ¬ num*10 + (c - '0); IF index = lastIndex THEN { IF num NOT IN (FSBackdoor.lowestVersion .. FSBackdoor.highestVersion) THEN EXIT; value ¬ [num]; vI ¬ number; RETURN; }; index ¬ index + 1; c ¬ Rope.Fetch[name, index]; IF c NOT IN ['0 .. '9] THEN EXIT; ENDLOOP; }; 'H, 'h => IF index = lastIndex THEN { value ¬ FSBackdoor.highestVersion; vI ¬ bangH; RETURN }; 'L, 'l => IF index = lastIndex THEN { value ¬ FSBackdoor.lowestVersion; vI ¬ bangL; RETURN }; '* => IF index = lastIndex AND pattern THEN { value ¬ FSBackdoor.highestVersion; vI ¬ bangStar; RETURN }; ENDCASE; IllegalVersion[name]; }; IllegalVersion: PROC [n: ROPE] = { ProduceError[ illegalName, QuotedName[n, " has an illegal version part"] ]; }; QuotedName: PROC [n, rest: ROPE] RETURNS [ROPE] = { RETURN [ Rope.Cat["\"", n, "\"", rest] ]; }; DebugExpandName: Commander.CommandProc ~ { ENABLE Error => {msg ¬ error.explanation; result ¬ $Failure; CONTINUE}; fullFName: ROPE; cp: FS.ComponentPositions; WHILE Rope.Match[" *", cmd.commandLine] DO cmd.commandLine ¬ Rope.Substr[cmd.commandLine, 1] ENDLOOP; cmd.commandLine ¬ Rope.Substr[cmd.commandLine, 0, cmd.commandLine.SkipTo[skip: "\l\r"]]; [fullFName, cp] ¬ ExpandName[cmd.commandLine]; IO.PutRope[cmd.out, fullFName]; IO.PutRope[cmd.out, "\n"]; IO.PutF[cmd.out, "[%g, %g], ", [integer[cp.server.start]], [integer[cp.server.length]]]; IO.PutF[cmd.out, "[%g, %g], ", [integer[cp.dir.start]], [integer[cp.dir.length]]]; IO.PutF[cmd.out, "[%g, %g], ", [integer[cp.subDirs.start]], [integer[cp.subDirs.length]]]; IO.PutF[cmd.out, "[%g, %g], ", [integer[cp.base.start]], [integer[cp.base.length]]]; IO.PutF[cmd.out, "[%g, %g], ", [integer[cp.ext.start]], [integer[cp.ext.length]]]; IO.PutF[cmd.out, "[%g, %g]\n", [integer[cp.ver.start]], [integer[cp.ver.length]]]; }; Commander.Register["DebugExpandName", DebugExpandName]; END.