MODULE M3Directory; (***************************************************************************) (* Copyright (C) Olivetti 1989 *) (* All Rights reserved *) (* *) (* Use and copy of this software and preparation of derivative works based *) (* upon this software are permitted to any person, provided this same *) (* copyright notice and the following Olivetti warranty disclaimer are *) (* included in any copy of the software or any modification thereof or *) (* derivative work therefrom made by any person. *) (* *) (* This software is made available AS IS and Olivetti disclaims all *) (* warranties with respect to this software, whether expressed or implied *) (* under any law, including all implied warranties of merchantibility and *) (* fitness for any purpose. In no event shall Olivetti be liable for any *) (* damages whatsoever resulting from loss of use, data or profits or *) (* otherwise arising out of or in connection with the use or performance *) (* of this software. *) (***************************************************************************) IMPORT CharType, DirOp, M3Assert, M3Extension, PathName, SList, Text, OSError; REVEAL T = BRANDED OBJECT d: Text.T; (* name of directory we're iterating *) e: M3Extension.TSet; (* extensions this iterator is interested in *) cache: SList.T; (* of CacheElem *) cacheBuilt: BOOLEAN := FALSE; ce: CacheElem := NIL; (* elem we've reached in the iteration *) END; TYPE CacheElem = SList.Elem OBJECT name: Text.T; ext: M3Extension.T; END; (*PUBLIC*) PROCEDURE New( d: Text.T; exts: M3Extension.TSet := M3Extension.TSet{FIRST(M3Extension.T)..LAST(M3Extension.T)}) : T RAISES {} = BEGIN RETURN NEW(T, d := d, e := exts); END New; (*PUBLIC*) PROCEDURE Next( t: T; VAR name: Text.T; VAR ext: M3Extension.T) : BOOLEAN RAISES {} = BEGIN IF NOT t.cacheBuilt THEN BuildCache(t); END; WHILE t.ce # NIL DO TRY (* finally on to next *) IF t.ce.ext IN t.e THEN name := t.ce.name; ext := t.ce.ext; RETURN TRUE; END; (* if we want this one *) FINALLY t.ce := t.ce.next; END; END; (* while entries in cache *) (* iterator failed *) name := ""; ext := M3Extension.T.Null; RETURN FALSE; END Next; (*PUBLIC*) PROCEDURE Rewind(t: T) RAISES {} = BEGIN IF t.cacheBuilt THEN t.ce := t.cache.head; END; END Rewind; (*PRIVATE*) PROCEDURE BuildCache(t: T) RAISES {} = BEGIN TRY (* finally cacheBuilt := TRUE *) t.cache.head := NIL; TRY VAR name: Text.T; ext: M3Extension.T; dir := DirOp.Open(t.d, mustExist := FALSE); dirIter: DirOp.Iterator := NIL; entry: DirOp.Entry; BEGIN IF dir = NIL THEN RETURN; END; WHILE DirOp.Next(dir, dirIter, entry) DO name := DirOp.EntryName(entry); IF M3Extension.Has(name, ext) (* returning the current directory as an m3 file messes us up, * because when we Concat "this.directory" with ".", we get * "this.directory", which does not have a good m3 extension. * ".." gets to be an m3file here too, but less harm is done. *) AND NOT Text.Equal(name, PathName.Current()) THEN AddToCache(t, PathName.Name(name), ext); END; (* if good one *) END; (* while iterating directory *) DirOp.Close(dir); END; (* var *) EXCEPT OSError.E => (* not a directory for example *) END; FINALLY t.cacheBuilt := TRUE; t.ce := t.cache.head; END; END BuildCache; (*PRIVATE*) PROCEDURE AddToCache(t: T; name: Text.T; ext: M3Extension.T) RAISES {} = BEGIN SList.AddFront(t.cache, NEW(CacheElem, name := name, ext := ext)); END AddToCache; BEGIN END M3Directory.