DIRECTORY FS USING [ComponentPositions, Error, ExpandName], FSExtras USING [CreateEvent, NextCreateEvent], MessageWindow USING [Append, Blink], Process USING [Detach], Rope USING [Cat, Equal, Fetch, Length, ROPE, Run], TEditDocumentPrivate USING [DoLoadFile], ViewerOps USING [EnumerateViewers, EnumProc]; TiogaFileWatcherImpl: CEDAR PROGRAM IMPORTS FS, FSExtras, MessageWindow, Process, Rope, TEditDocumentPrivate, ViewerOps = BEGIN ROPE: TYPE = Rope.ROPE; highestVersion: CARDINAL ~ CARDINAL.LAST; ExtensionType: TYPE = {nil, tip, style}; Info: TYPE = RECORD[ name: ROPE _ NIL, -- full FName len: INT _ 0, -- length of name, omitting version part version: CARDINAL _ highestVersion, -- version number type: ExtensionType _ nil -- extension type ]; ParseFileName: PROC[name: ROPE] RETURNS[info: Info _ []] = { cp: FS.ComponentPositions; [fullFName: name, cp: cp] _ FS.ExpandName[name ! FS.Error => GOTO Fail]; info.name _ name; -- full name info.len _ cp.ext.start+cp.ext.length; -- length up to end of extension IF cp.ver.length>0 THEN { -- parse version number start: INT ~ cp.ver.start; len: INT ~ cp.ver.length; version: CARDINAL _ 0; FOR i: INT IN[start..start+len) DO version _ version*10+(name.Fetch[i]-'0); ENDLOOP; info.version _ version; }; IF cp.ext.length>0 THEN { -- look for special extensions start: INT ~ cp.ext.start; len: INT ~ cp.ext.length; MatchExtension: PROC[x: ROPE] RETURNS[BOOL] = { RETURN[Rope.Length[x]=len AND Rope.Run[s1: name, pos1: start, s2: x, case: FALSE]=len] }; SELECT TRUE FROM MatchExtension["tip"] => info.type _ tip; MatchExtension["style"] => info.type _ style; ENDCASE; }; EXITS Fail => RETURN; }; NamesMatch: PROC[a, b: Info] RETURNS[BOOL] = { RETURN[a.len=b.len AND Rope.Run[s1: a.name, s2: b.name, case: FALSE]>=a.len]; }; stop: BOOL _ FALSE; TiogaFileWatcher: PROC = { event: REF READONLY FSExtras.CreateEvent _ NIL; old, new: Info; DO editingOldVersion: BOOL _ FALSE; action: ViewerOps.EnumProc -- [v: Viewer] -- = { IF v.class.flavor#$Text THEN RETURN; IF v.destroyed OR v.saveInProgress THEN RETURN; IF Rope.Equal[s1: v.name, s2: v.file, case: FALSE] THEN RETURN; -- explicit version old _ ParseFileName[v.file]; IF NamesMatch[old, new] AND new.version>old.version THEN { IF v.destroyed THEN NULL ELSE IF v.newVersion THEN editingOldVersion _ TRUE ELSE [] _ TEditDocumentPrivate.DoLoadFile[parent: v, fileName: v.name]; }; }; event _ FSExtras.NextCreateEvent[event]; IF stop THEN EXIT; new _ ParseFileName[event.fName]; ViewerOps.EnumerateViewers[action]; IF editingOldVersion THEN { MessageWindow.Append[message: Rope.Cat[ "Warning: ", new.name, " was created while you were editing an older version."], clearFirst: TRUE]; MessageWindow.Blink[]; }; ENDLOOP; }; Start: PROC = { stop _ FALSE; TRUSTED { Process.Detach[FORK TiogaFileWatcher] }; }; Stop: PROC = { stop _ TRUE }; Start[]; END. vTiogaFileWatcherImpl.mesa Last edited by Doug Wyatt, December 15, 1983 7:15 pm Crock: if v.saveInProgress, SaveViewer may have just written the file but not fixed up v.file and v.newVersion yet. Since SaveViewer doesn't lock the viewer there seems to be no good way to synchronize this properly. Assume the following convention for v.name and v.file in a $Text viewer v: v.file always contains the full FName obtained from FS.GetName If an explicit version was requested, then v.name matches v.file; otherwise, v.name contains v.file with the version part omitted. SELECT new.type FROM tip => xxx; style => xxx; ENDCASE; ĘY˜šœ™J™4J™—šĎk ˜ Jšœœ)˜1Jšœ œ ˜.Jšœœ˜$Jšœœ ˜Jšœœœ˜2Jšœœ˜(Jšœ œ˜-J˜—Jšœœ˜#JšœœI˜SJšœ˜J˜Jšœœœ˜J˜Jšœœœœ˜)Jšœœ˜(šœœœ˜JšœœœĎc ˜Jšœœž(˜6Jšœ œž˜5Jšœž˜+Jšœ˜—J˜šĎn œœœœ˜J™‚—Jš œ*œœœž˜SJšœ˜šœœœ˜:Jšœ œ˜Jšœœœ˜2JšœC˜GJ˜—J˜—Jšœ(˜(Jšœœœ˜Jšœ!˜!šœ ™J™ J™ Jšœ™—J˜#šœœ˜˜'JšœP˜PJšœ œ˜—J˜Jšœ˜—Jšœ˜—J˜J˜—šŸœœ˜Jšœœ˜ Jšœœ˜2J˜—J˜JšŸœœ œ˜J˜J˜J˜Jšœ˜—…— &ő