(* Copyright (C) 1990, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) MODULE M3DepM3Path; IMPORT SList, IO, IOErr, DirOp, Fmt, Err, HashText, Text, FileStamp, PathName, OSError; IMPORT M3FindFile, M3Path, M3Extension, M3Files_m3p, M3CUnit, M3CUnit_priv; REVEAL T = BRANDED REF RECORD finder: M3Path.Finder; objLibTable: HashText.Table; END; PROCEDURE Scan(): T RAISES {}= VAR t := NEW(T, objLibTable := HashText.New()); BEGIN (* create a finder (for all source extensions, so that it will be used by M3Files later), and then iterate it, recording the timestamps on modules and interfaces. *) M3Path.EnsureCurrentFirst(); (* always want current dir *) TRY t.finder := M3Path.Find( M3Extension.TSet{M3Extension.T.Int, M3Extension.T.IntG, M3Extension.T.PInt, M3Extension.T.Mod, M3Extension.T.ModG, M3Extension.T.ObjLib}, forceRead := TRUE); EXCEPT | M3Path.BadDirName(n) => Err.Print(Fmt.F("bad directory on m3path:\'%s\'\n", n), Err.Severity.Warning); | IO.Error(s) => IOErr.Close(s, Err.Severity.Warning); END; (* try *) M3Files_m3p.SetFinder(t.finder); VAR dirList := M3Path.FinderDirs(t.finder); dir: M3Path.Elem := dirList.head; BEGIN WHILE dir # NIL DO IF NOT DirOp.Accessible(dir.text) THEN Err.Print(Fmt.F("inaccessible directory on m3path: \'%s\'\n", dir.text), Err.Severity.Warning); END; (* if inaccessible *) dir := dir.next; END; (* while *) END; (* begin *) VAR iter := M3Path.NewIter(t.finder); unitName: TEXT; dir: M3Path.Elem; ext: M3Extension.T; BEGIN WHILE M3Path.Next(iter, unitName, ext, dir) DO IF ext IN M3Extension.Ints OR ext IN M3Extension.Mods THEN IF M3Path.GetProperty(t.finder, unitName, ext) = NIL THEN VAR fullName := PathName.Full(dir.text, M3Extension.Extend(unitName, ext)); BEGIN TRY M3Path.SetProperty(t.finder, unitName, ext, FileStamp.Get(fullName)); EXCEPT OSError.E(e) => Err.Print( Fmt.F("problem reading timestamp for %s - %s\n", fullName, OSError.ToText(e)), Err.Severity.Warning); END; END; END; ELSIF ext = M3Extension.T.ObjLib THEN VAR id: HashText.Id; BEGIN IF HashText.Enter(t.objLibTable, dir.text, id) THEN HashText.Associate(t.objLibTable, id, unitName); ELSE Err.Print(Fmt.F( "directory \'%s\' contains more than one archive - \'%s\' ignored", dir.text, M3Extension.Extend(unitName, ext)), Err.Severity.Warning); END; (* if *) END; END; (* if *) END; (* while *) END; RETURN t; END Scan; PROCEDURE Dirs(t: T): SList.T RAISES {}= BEGIN RETURN M3Path.FinderDirs(t.finder); END Dirs; PROCEDURE ValidateDir(t: T; dirName: TEXT): M3Path.Elem RAISES {}= VAR dir: M3Path.Elem := M3Path.FinderDirs(t.finder).head; dirElem := M3Path.ElemFrom(dirName); BEGIN WHILE dir # NIL DO IF M3Path.Same(dir, dirElem) THEN RETURN dir ELSE dir := dir.next END; END; RETURN NIL; END ValidateDir; PROCEDURE DirObjLib(t: T; dir: M3Path.Elem): TEXT RAISES {}= VAR id: HashText.Id; BEGIN IF HashText.Lookup(t.objLibTable, dir.text, id) THEN RETURN M3Extension.Extend(HashText.Value(t.objLibTable, id), M3Extension.T.ObjLib); ELSE RETURN NIL; END; (* if *) END DirObjLib; PROCEDURE DirOf(t: T; ut: M3CUnit.Type; name: TEXT): M3Path.Elem RAISES {}= VAR exts: M3Extension.TSet; nameElem: M3Path.Elem; void: M3Extension.T; BEGIN IF ut = M3CUnit.Type.Interface THEN exts := M3Extension.Ints; ELSE exts := M3Extension.Mods END; RETURN FindFromSet(t, name, exts, void); END DirOf; PROCEDURE FindFromSet( t: T; name: TEXT; exts: M3Extension.TSet; VAR (*out*) ext: M3Extension.T) : M3Path.Elem RAISES {M3FindFile.Failed}= BEGIN FOR e := FIRST(M3Extension.T) TO LAST(M3Extension.T) DO IF e IN exts THEN ext := e; TRY RETURN t.finder.findDir(name, e); EXCEPT M3FindFile.Failed => END; END; (* if *) END; (* for *) RAISE M3FindFile.Failed; END FindFromSet; PROCEDURE Interfaces( oldt, t: T; VAR (*out*) u: UpdateRec; inDir: M3Path.Elem := NIL) RAISES {}= BEGIN Units(oldt, t, u, inDir, M3Extension.Ints); END Interfaces; PROCEDURE Modules( oldt, t: T; VAR (*out*) u: UpdateRec; inDir: M3Path.Elem := NIL) RAISES {}= BEGIN Units(oldt, t, u, inDir, M3Extension.Mods); END Modules; PROCEDURE Units(oldt, t: T; VAR (*out*) u: UpdateRec; thisDirElem: M3Path.Elem; wantedExts: M3Extension.TSet;) RAISES {}= VAR iter: M3Path.Iter; ext: M3Extension.T; unitName: TEXT; new: BOOLEAN; dirElem, oldDirElem: M3Path.Elem; BEGIN FOR a := FIRST(Update) TO LAST(Update) DO u[a].head := NIL END; (* generate 'Deleted' array *) IF oldt # NIL THEN iter := M3Path.NewIter(oldt.finder); WHILE M3Path.Next(iter, unitName, ext, dirElem) DO IF ext IN wantedExts THEN TRY EVAL t.finder.find(unitName, ext); EXCEPT | M3FindFile.Failed => SList.AddRear(u[Update.Deleted], NEW(SList.TextElem, text := unitName)); END; END; (* if *) END; (* while *) END; (* if *) (* generate 'Changed' and 'Added' *) iter := M3Path.NewIter(t.finder); WHILE M3Path.Next(iter, unitName, ext, dirElem) DO IF ext IN wantedExts THEN IF thisDirElem = NIL OR M3Path.Same(dirElem, thisDirElem) THEN new := TRUE; IF oldt # NIL THEN TRY oldDirElem := oldt.finder.findDir(unitName, ext); (* Ok, existed before, check directory *) IF M3Path.Same(dirElem, oldDirElem) THEN new := FALSE; (* ok, check timestamp *) VAR f1 := NARROW(M3Path.GetProperty(oldt.finder, unitName, ext), FileStamp.T); f2 := NARROW(M3Path.GetProperty(t.finder, unitName, ext), FileStamp.T); BEGIN IF (f1 # f2) AND NOT FileStamp.Compare(f1, f2) = 0 THEN SList.AddRear(u[Update.Changed], NEW(SList.TextElem, text := unitName)); END; (* if *) END; ELSE (* Changed directory! Treat this as Deleted + Added *) SList.AddRear(u[Update.Deleted], NEW(SList.TextElem, text := unitName)); END; (* if *) EXCEPT | M3FindFile.Failed => (* new is TRUE *) END; END; IF new THEN (* brand new unit *) SList.AddRear(u[Update.Added], NEW(SList.TextElem, text := unitName)); END; END; END; (* if *) END; (* while *) END Units; PROCEDURE RealHead(t: TEXT): TEXT RAISES {}= VAR h := PathName.Head(t); l := Text.Length(h); BEGIN (* removes trailing '/', if any from PathName.Head call. *) IF l # 0 AND Text.GetChar(h, l-1) = PathName.DirSepCh() THEN RETURN Text.Sub(h, 0, l-1); ELSE RETURN h; END; END RealHead; PROCEDURE UidEqual(t: T; name: TEXT; ut: M3CUnit.Type; uid: M3CUnit.Uid): BOOLEAN RAISES {}= VAR ext: M3Extension.T; dirElem := FindFromSet(t, name, ExtsFromUt(ut), ext); fullName: TEXT := PathName.Full(dirElem.text, M3Extension.Extend(name, ext)); fs: FileStamp.T; BEGIN fs := M3Path.GetProperty(t.finder, name, ext); RETURN Text.Equal(fullName, uid.filename) AND FileStamp.Compare(fs, uid.stamp) = 0; END UidEqual; PROCEDURE InfoOf(t: T; ut: M3CUnit.Type; name: TEXT): Info= VAR info: Info; BEGIN TRY VAR ext: M3Extension.T; dirElem := FindFromSet(t, name, ExtsFromUt(ut), ext); BEGIN info.pathName := PathName.Full(dirElem.text, M3Extension.Extend(name, ext)); info.timeStamp := M3Path.GetProperty(t.finder, name, ext); END; EXCEPT M3FindFile.Failed => END; RETURN info; END InfoOf; PROCEDURE ExtsFromUt(ut: M3CUnit.Type): M3Extension.TSet RAISES {}= BEGIN IF ut = M3CUnit.Type.Interface THEN RETURN M3Extension.Ints ELSE RETURN M3Extension.Mods; END; END ExtsFromUt; BEGIN END M3DepM3Path.