"Syntax10.Scn.FntJAStampElemsAlloc8 Apr 96i`_VersionElemsAllocBeg#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMac `_VersionElemsAllocEnd#8FoldElemsNew$Syntax10i.Scn.FntRevision HistorySyntax10i.Scn.Fnt8r`_#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMac*Syntax10.Scn.Fnt , Macintosh, Sys`_ `_#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMacQSyntax10.Scn.FntSyntax10i.Scn.Fnt#?noErr = Directories.noErr; (* no error *) eofErr = -39; (* logical end of file reached *) fnfErr = -43; (* directory not found or incomplete pathname *)`_qSyntax10b.Scn.Fnt M M ) *8F8*8S8!88 8q8 /88 +8p8`_#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMac]Syntax10.Scn.FntSyntax10b.Scn.Fnt38FoldElemsNew#Syntax10.Scn.Fnt@@ VAR c1, c2: CHAR; i: INTEGER; BEGIN i := 0; LOOP c1 := elem.name[i]; c2 := name[i]; IF ("a" <= c1) & (c1 <= "z") THEN c1 := CAP(c1) END; IF ("a" <= c2) & (c2 <= "z") THEN c2 := CAP(c2) END; IF (c1 = 0X) & (c2 = 0X) THEN RETURN TRUE ELSIF c1 # c2 THEN RETURN FALSE END; INC(i) END END CheckIdentity; 8q8#Syntax10.Scn.Fnt?? VAR e: FMElems.Elem; f: FolderElem; dir: Directories.Directory; path: FMDevObj.Path; size, date, time: LONGINT; file: Files.File; fullName: FMDevObj.Path; BEGIN continue := TRUE; IF isDir THEN COPY(d.path, path); devObj.Append(path, name); dir := Directories.This(path); IF dir = NIL THEN RETURN END; NEW(f); InitFolderElem(f, name, folder.pattern, folder.sortOrder, folder.attributes, FALSE, dir); enumerateList.Insert(f) ELSIF Strings.Match(name, pat) THEN size := 0; date := 0; time := 0; IF setData THEN COPY(d.path, fullName); devObj.Append(fullName, name); file := Files.Old(fullName); IF file # NIL THEN Files.GetDate(file, time, date); size := Files.Length(file) END END; NEW(e); FMElems.InitElem(e, name, size, date, time); enumerateList.Insert(e) END END InsertDirEntry; 8PROCEDURE (d: Device) CheckIdentity* (elem: FMElems.Elem; name: ARRAY OF CHAR): BOOLEAN; PROCEDURE InsertDirEntry (d: Directories.Directory; name: ARRAY OF CHAR; isDir: BOOLEAN; VAR continue: BOOLEAN);38=8q8v8`_ K88A8878n8 T88 C88 C88 388288r8G8K88O8A88?888`_#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMac Syntax10.Scn.Fnt8FoldElemsNew#Syntax10.Scn.Fnt BEGIN info.ioCompletion := 0; info.ioNamePtr := SYSTEM.ADR(str255); info.ioVRefNum := vRefNum; info.ioDirID := parID; info.ioFDirIndex := index; RETURN (Sys.PBGetCatInfo(SYSTEM.VAL(Sys.CInfoPBFilePtr, SYSTEM.ADR(info))) = noErr) END GetFileDirInfo; 8'8#Syntax10.Scn.Fnt VAR len: LONGINT; res: INTEGER; BEGIN len := BufSize; res := Sys.FSRead(src, len, SYSTEM.ADR(buf^)); WHILE res = noErr DO res := Sys.FSWrite(des, len, SYSTEM.ADR(buf^)); ASSERT(res = 0, 99); len := BufSize; res := Sys.FSRead(src, len, SYSTEM.ADR(buf^)) END; ASSERT (res = eofErr, 98); IF len # 0 THEN res := Sys.FSWrite(des, len, SYSTEM.ADR(buf^)); ASSERT(res = 0, 99); END; res := Sys.FSClose(src); res := Sys.FSClose(des) END CopyData; 88!8#Syntax10.Scn.Fnt VAR info: Sys.CInfoPBFileRec; src, des: INTEGER; res: INTEGER; len: LONGINT; BEGIN IF GetFileDirInfo(srcSpec.vRefNum, srcSpec.parID, 0, srcSpec.name, info) THEN res := Sys.FSpCreate(desSpec, info.ioFlFndrInfo.fdCreator, info.ioFlFndrInfo.fdType, Sys.smSystemScript); IF res # noErr THEN RETURN FALSE END; IF Sys.FSpOpenDF(srcSpec, 0, src) # noErr THEN RETURN FALSE END; IF Sys.FSpOpenDF(desSpec, 0, des)# noErr THEN RETURN FALSE END; CopyData(src, des); IF info.ioFlRLgLen > 0 THEN res := Sys.FSpOpenRF(srcSpec, 0, src); ASSERT(res = 0, 95); res := Sys.FSpOpenRF(desSpec, 0, des); ASSERT(res = 0, 94); CopyData(src, des); END; RETURN TRUE END; RETURN FALSE END Copy; 8Syntax10b.Scn.FntX8#Syntax10.Scn.Fnt VAR srcSpec, destSpec: Sys.FSSpec; str255: Sys.Str255; reader: FMDevObj.Reader; fullName: FMDevObj.Path; file: Files.File; r: Files.Rider; len, res: INTEGER; BEGIN d.done := FALSE; WITH destParent: FolderElem DO IF srcDev IS Device THEN WITH srcParent: FolderElem DO Macintosh.SetStr255(str255, elem.name); res := Sys.FSMakeFSSpec(destParent.dir.spec.vRefNum, destParent.dir.dirID, str255, destSpec); IF (res = fnfErr) & (Sys.FSMakeFSSpec(srcParent.dir.spec.vRefNum, srcParent.dir.dirID, str255, srcSpec) = noErr) THEN d.done := Copy(srcSpec, destSpec); IF d.done THEN Directories.notify(FMDevObj.insert, destParent.dir.path, elem.name) END END ELSE END ELSE reader:= srcDev.NewReader(srcParent, elem); COPY(destParent.dir.path, fullName); d.Append(fullName, elem.name); file := Files.New(fullName); IF (reader # NIL) & (file # NIL) THEN Files.Set(r, file, 0); reader.GetBytes(buf^, len); WHILE len > 0 DO Files.WriteBytes(r, buf^, len); reader.GetBytes(buf^, len) END; IF len = 0 THEN Files.Register(file); d.done := TRUE END END END ELSE END; IF ~d.done THEN LogString(" file copying failed"); LogLn END END Copy; 8l PROCEDURE GetFileDirInfo(vRefNum: INTEGER; parID: LONGINT; index: INTEGER; VAR str255: ARRAY OF CHAR; VAR info: Sys.CInfoPBFileRec): BOOLEAN; PROCEDURE CopyData(src, des: INTEGER); PROCEDURE Copy (srcSpec, desSpec: Sys.FSSpec): BOOLEAN; PROCEDURE (d: Device) Copy* (destParent, srcParent: FMElems.FolderElem; elem: FMElems.Elem; srcDev: FMDevObj.Device); X88`_Z88`_#Syntax10.Scn.FntWindows PowerMacWindowsWindows PowerMacSyntax10.Scn.FntSyntax10b.Scn.Fnt`8FoldElemsNew#Syntax10.Scn.Fnt VAR oldFullName, newFullName: FMDevObj.Path; BEGIN d.done := FALSE; WITH destParent: FolderElem DO WITH srcParent: FolderElem DO COPY(srcParent.dir.path, oldFullName); d.Append(oldFullName, elem.name); COPY(destParent.dir.path, newFullName); d.Append(newFullName, elem.name); Directories.Rename(oldFullName, newFullName); d.done := Directories.res = noErr ELSE END ELSE END; IF ~d.done THEN LogString(elem.name); LogString(" moving failded"); LogLn END END MoveDir; 8PROCEDURE (d: Device) MoveDir* (destParent, srcParent: FMElems.FolderElem; elem: FMElems.FolderElem; srcDev: FMDevObj.Device);`88`_ 2808  88<8I8^8888/88IMODULE FMSysDevObj; (* Christian Maryhofer, 24 Jan 96; Gnter Obiltschnig  *) (* This module contains two versions. Versions: - PowerMac - Windows To switch versions click on  with the middle mouse button. *)  (**************************************************** Revision History: 960126: GO added Writer object ****************************************************)  IMPORT SYSTEM, Directories, Files, Kernel, MenuViewers, Oberon, Strings, Texts, TextFrames, Viewers, FMDevObj, FMElems, FMFrames; CONST noErr = Directories.noErr; (* no error *) BufSize = 4096; N = 64; ConfigurationFile = "FileManager.Profile"; menu = "^FileManager.Menu.Text"; TYPE Reader* = POINTER TO ReaderDesc; ReaderDesc* = RECORD (FMDevObj.ReaderDesc) file: Files.File; r: Files.Rider END; Writer* = POINTER TO WriterDesc; (* GO 270196 *) WriterDesc* = RECORD (FMDevObj.WriterDesc) file: Files.File; r: Files.Rider END; Device* = POINTER TO DeviceDesc; DeviceDesc* = RECORD (FMDevObj.DeviceDesc) END; FolderElem* = POINTER TO FolderElemDesc; FolderElemDesc* = RECORD (FMElems.FolderElemDesc) dir: Directories.Directory END; Pattern = ARRAY 8 OF CHAR; Node = POINTER TO NodeDesc; NodeDesc = RECORD cmd: ARRAY N OF CHAR; patterns: POINTER TO ARRAY OF Pattern; next: Node; withPath: BOOLEAN END; VAR oldNotifier: Directories.Notifier; trashE: FolderElem; trashPath: FMDevObj.Path; buf: POINTER TO ARRAY OF CHAR; applicationList: Node; w: Texts.Writer; enumerateList: FMDevObj.List; setData: BOOLEAN; devObj: Device; folder: FolderElem; pat, dosPat: FMElems.Name; PROCEDURE LogLn (); BEGIN Texts.WriteLn(w); Texts.Append(Oberon.Log, w.buf) END LogLn;  PROCEDURE LogString (str: ARRAY OF CHAR); BEGIN Texts.WriteString(w, str); Texts.Append(Oberon.Log, w.buf) END LogString;  PROCEDURE (folder: FolderElem) Copy* (VAR de: Texts.Elem); VAR clone: FolderElem; BEGIN IF de = NIL THEN NEW(clone); de := clone END; folder.Copy^(de); de(FolderElem).dir := folder.dir END Copy;  PROCEDURE InitFolderElem*(e: FolderElem; name, pattern, sortOrder: ARRAY OF CHAR; VAR attributes: FMElems.Attributes; open: BOOLEAN; dir: Directories.Directory); BEGIN FMElems.InitFolderElem(e, name, pattern, sortOrder, attributes, open); e.dir := dir END InitFolderElem;  PROCEDURE (r: Reader) GetBytes* (VAR buffer: ARRAY OF CHAR; VAR len: INTEGER); BEGIN len := SHORT(LEN(buffer)); Files.ReadBytes(r.r, buffer, len); IF r.r.eof THEN len := len - SHORT(r.r.res) END END GetBytes;  PROCEDURE (w: Writer) PutBytes* (VAR buffer: ARRAY OF CHAR; len: INTEGER); BEGIN IF len = 0 THEN Files.Register(w.file) ELSE Files.WriteBytes(w.r, buffer, len) END END PutBytes;  (* GO 270196 *) PROCEDURE (d: Device) CheckIdentity* (elem: FMElems.Elem; name: ARRAY OF CHAR): BOOLEAN; VAR i: INTEGER; c1, c2: CHAR; BEGIN IF (elem IS FMElems.FolderElem) OR ((name[0] = "&") & (elem.name[0] = "&")) THEN i := 0; LOOP c1 := elem.name[i]; c2 := name[i]; IF ("a" <= c1) & (c1 <= "z") THEN c1 := CAP(c1) END; IF ("a" <= c2) & (c2 <= "z") THEN c2 := CAP(c2) END; IF (c1 = 0X) & (c2 = 0X) THEN RETURN TRUE ELSIF c1 # c2 THEN RETURN FALSE END; INC(i) END ELSE i := 0; LOOP IF (elem.name[i] = 0X) & (name[i] = 0X) THEN RETURN TRUE ELSIF elem.name[i] # name[i] THEN RETURN FALSE END; INC(i) END END END CheckIdentity;  PROCEDURE InsertDirEntry (d: Directories.Directory; name: ARRAY OF CHAR; isDir: BOOLEAN; VAR continue: BOOLEAN); VAR e: FMElems.Elem; f: FolderElem; dir: Directories.Directory; path: FMDevObj.Path; size, date, time: LONGINT; file: Files.File; fullName: FMDevObj.Path; i: INTEGER; str: FMElems.Name; BEGIN continue := TRUE; IF (name = ".") OR (name = "..") THEN RETURN END; IF isDir THEN COPY(d.path, path); devObj.Append(path, name); dir := Directories.This(path); IF dir = NIL THEN RETURN END; NEW(f); InitFolderElem(f, name, folder.pattern, folder.sortOrder, folder.attributes, FALSE, dir); enumerateList.Insert(f) ELSE IF name[0] = "&" THEN i := 1; WHILE name[i] # 0X DO str[i-1] := name[i]; INC(i) END; str[i-1] := 0X; Strings.Cap(str) END; IF ((name[0] = "&") & Strings.Match(str, dosPat)) OR ((name[0] # "&") & Strings.Match(name, pat)) THEN size := 0; date := 0; time := 0; IF setData THEN COPY(d.path, fullName); devObj.Append(fullName, name); file := Files.Old(fullName); IF file # NIL THEN Files.GetDate(file, time, date); size := Files.Length(file) END END; NEW(e); FMElems.InitElem(e, name, size, date, time); enumerateList.Insert(e) END END END InsertDirEntry;  PROCEDURE (d: Device) Enumerate* (parent: FMElems.FolderElem; list: FMDevObj.List; pattern: ARRAY OF CHAR); VAR i, n: INTEGER; BEGIN WITH parent: FolderElem DO enumerateList := list; folder := parent; COPY(pattern, pat); COPY(pattern, dosPat); Strings.Cap(dosPat); devObj := d; setData := FALSE; i := 0; n := parent.attributes.nOfAttributes; WHILE ~setData & (i < n) DO setData := (parent.attributes.names[i] = FMElems.showDate) OR (parent.attributes.names[i] = FMElems.showSize); INC(i) END; Directories.Enumerate(parent.dir, InsertDirEntry); ELSE END END Enumerate;  PROCEDURE (d: Device) GetElem* (parent: FMElems.FolderElem; name: ARRAY OF CHAR): FMElems.Elem; VAR e: FMElems.Elem; dir: Directories.Directory; fullName: FMDevObj.Path; f: FolderElem; file: Files.File; size, date, time: LONGINT; BEGIN WITH parent: FolderElem DO COPY(parent.dir.path, fullName); d.Append(fullName, name); dir := Directories.This(fullName); IF dir # NIL THEN NEW(f); InitFolderElem(f, name, parent.pattern, parent.sortOrder, parent.attributes, FALSE, dir); RETURN f ELSE file := Files.Old(fullName); IF file # NIL THEN Files.GetDate(file, time, date); size := Files.Length(file); NEW(e); FMElems.InitElem(e, name, size, date, time); RETURN e END END ELSE END; RETURN NIL END GetElem;  PROCEDURE (d: Device) GetPath* (folder: FMElems.FolderElem; VAR path: ARRAY OF CHAR); BEGIN WITH folder: FolderElem DO COPY(folder.dir.path, path); Strings.Cap(path) ELSE END END GetPath;  PROCEDURE (d: Device) GetTrash* (VAR attributes: FMElems.Attributes; sortOrder: ARRAY OF CHAR): FMElems.FolderElem; VAR f: FolderElem; pattern: ARRAY 2 OF CHAR; BEGIN IF trashE # NIL THEN pattern := "*"; NEW(f); InitFolderElem(f, trashE.name, pattern, sortOrder, attributes, FALSE, trashE.dir); RETURN f END; RETURN NIL END GetTrash;  PROCEDURE (d: Device) NewReader* (parent: FMElems.FolderElem; elem: FMElems.Elem): FMDevObj.Reader; VAR r: Reader; fullName: FMDevObj.Path; BEGIN d.GetPath(parent, fullName); d.Append(fullName, elem.name); NEW(r); r.file := Files.Old(fullName); IF r.file # NIL THEN Files.Set(r.r, r.file, 0); RETURN r END; RETURN NIL END NewReader;  PROCEDURE (d: Device) NewWriter* (parent: FMElems.FolderElem; elem: FMElems.Elem): FMDevObj.Writer; VAR w: Writer; fullName: FMDevObj.Path; BEGIN d.GetPath(parent, fullName); d.Append(fullName, elem.name); NEW(w); w.file := Files.New(fullName); IF w.file # NIL THEN Files.Set(w.r, w.file, 0); RETURN w END; RETURN NIL END NewWriter;  PROCEDURE (d: Device) NewDirectory* (parent: FMElems.FolderElem; name: ARRAY OF CHAR); VAR fullName: FMDevObj.Path; BEGIN d.done := FALSE; WITH parent: FolderElem DO COPY(parent.dir.path, fullName); d.Append(fullName, name); Directories.Create(fullName); d.done := Directories.res = noErr; ELSE END END NewDirectory;  PROCEDURE (d: Device) Open* (parent: FMElems.FolderElem; elem: FMElems.Elem); VAR curr: Node; found: BOOLEAN; w: Texts.Writer; i: INTEGER; e: FMElems.Elem; path: FMDevObj.Path; x, y: INTEGER; v: Viewers.Viewer; PROCEDURE CallCmd (cmd, path, name: ARRAY OF CHAR); VAR par: Oberon.ParList; res: INTEGER; BEGIN NEW(par); par.text := TextFrames.Text(""); par.frame := TextFrames.NewText(par.text, 0); par.pos := 0; Texts.Write(w, '"'); Texts.WriteString(w, path); Texts.WriteString(w, name); Texts.Write(w, '"'); Texts.Write(w, "~"); Texts.Append(par.text, w.buf); Oberon.Call(cmd, par, FALSE, res) END CallCmd;  BEGIN Texts.OpenWriter(w); IF elem IS FMElems.FolderElem THEN e := d.GetElem(parent, elem.name); IF e = NIL THEN RETURN END; Oberon.AllocateSystemViewer(Oberon.Par.vwr.X, x, y); v := MenuViewers.New(TextFrames.NewMenu(e(FolderElem).dir.path, menu), FMFrames.NewFrame(FMFrames.NewText(d, e(FolderElem))), TextFrames.menuH, x, y) ELSE found := FALSE; curr := applicationList; WHILE (curr # NIL) & ~found DO i := SHORT(LEN(curr.patterns^)) - 1; WHILE (i >= 0) & ~Strings.Match(elem.name, curr.patterns[i]) DO DEC(i) END; IF (i >= 0) THEN found := TRUE ELSE curr := curr.next END END; d.GetPath(parent, path); d.Append(path, ""); IF found THEN IF ~curr.withPath THEN path[0] := 0X END; CallCmd(curr.cmd, path, elem.name) ELSE CallCmd("Edit.Open", path, elem.name) END END END Open;  PROCEDURE (d: Device) Rename* (parent: FMElems.FolderElem; elem: FMElems.Elem; VAR name: ARRAY OF CHAR); VAR oldFullName, newFullName: FMDevObj.Path; res: INTEGER; BEGIN d.done := FALSE; WITH parent: FolderElem DO IF d.GetElem(parent, name) = NIL THEN COPY(parent.dir.path, oldFullName); d.Append(oldFullName, elem.name); COPY(parent.dir.path, newFullName); d.Append(newFullName, name); IF elem IS FMElems.FolderElem THEN Directories.Rename(oldFullName, newFullName); d.done := Directories.res = noErr ELSE Files.Rename(oldFullName, newFullName, res); d.done := res = noErr END END ELSE END END Rename;  PROCEDURE (d: Device) Delete (parent: FMElems.FolderElem; elem: FMElems.Elem); PROCEDURE DeleteFile (parent: FolderElem; elem: FMElems.Elem); VAR fullName: FMDevObj.Path; res: INTEGER; BEGIN COPY(parent.dir.path, fullName); d.Append(fullName, elem.name); Files.Delete(fullName, res); d.done := res = noErr; IF ~d.done THEN LogString(elem.name); LogString(" deleted failded"); LogLn END END DeleteFile;  PROCEDURE DeleteDir (parent: FolderElem; elem: FMElems.Elem); VAR list: FMDevObj.List; iter: FMDevObj.Iterator; e: FMElems.Elem; msg: FMDevObj.NotifyMsg; fullName: FMDevObj.Path; BEGIN WITH elem: FolderElem DO COPY(parent.dir.path, fullName); d.Append(fullName, elem.name); list := d.NewSortList(elem); d.Enumerate(elem, list, "*"); iter := FMDevObj.NewIterator(list); IF iter # NIL THEN WHILE iter.NextElem(e) DO IF e IS FolderElem THEN DeleteDir(elem, e(FolderElem)) ELSE DeleteFile(elem, e) END END END; Kernel.GC(TRUE); Directories.Delete(fullName); d.done := Directories.res = noErr; IF ~d.done THEN LogString(elem.name); LogString(" deleted failded"); LogLn END END END DeleteDir; BEGIN WITH parent: FolderElem DO WITH elem: FolderElem DO DeleteDir(parent, elem) ELSE DeleteFile(parent, elem); Kernel.GC(TRUE) END ELSE END END Delete;  PROCEDURE (d: Device) Copy* (destParent, srcParent: FMElems.FolderElem; elem: FMElems.Elem; srcDev: FMDevObj.Device); VAR reader: FMDevObj.Reader; fullName: FMDevObj.Path; file: Files.File; r: Files.Rider; len: INTEGER; BEGIN d.done := FALSE; WITH destParent: FolderElem DO reader:= srcDev.NewReader(srcParent, elem); COPY(destParent.dir.path, fullName); d.Append(fullName, elem.name); file := Files.New(fullName); IF (reader # NIL) & (file # NIL) THEN Files.Set(r, file, 0); reader.GetBytes(buf^, len); WHILE len > 0 DO Files.WriteBytes(r, buf^, len); reader.GetBytes(buf^, len) END; IF len = 0 THEN Files.Register(file); d.done := TRUE END END ELSE END; IF ~d.done THEN LogString(" file copying failed"); LogLn END END Copy;  PROCEDURE (d: Device) Move* (destParent, srcParent: FMElems.FolderElem; elem: FMElems.Elem; srcDev: FMDevObj.Device); VAR oldFullName, newFullName: FMDevObj.Path; res: INTEGER; BEGIN d.done := FALSE; WITH destParent: FolderElem DO WITH srcParent: FolderElem DO COPY(srcParent.dir.path, oldFullName); d.Append(oldFullName, elem.name); COPY(destParent.dir.path, newFullName); d.Append(newFullName, elem.name); Files.Rename(oldFullName, newFullName, res); d.done := res = noErr ELSE END ELSE END; IF ~d.done THEN LogString(elem.name); LogString(" moving failded"); LogLn END END Move;  PROCEDURE (d: Device) MoveDir* (destParent, srcParent: FMElems.FolderElem; elem: FMElems.FolderElem; srcDev: FMDevObj.Device); VAR list: FMDevObj.List; iter: FMDevObj.Iterator; e, p: FMElems.Elem; fullName: FMDevObj.Path; BEGIN d.done := FALSE; WITH destParent: FolderElem DO IF (srcParent IS FolderElem) & (elem IS FolderElem) THEN d.NewDirectory(destParent, elem.name); p := d.GetElem(destParent, elem.name); IF p # NIL THEN list := srcDev.NewSortList(elem); srcDev.Enumerate(elem(FolderElem), list, "*"); iter := FMDevObj.NewIterator(list); IF iter # NIL THEN WHILE iter.NextElem(e) DO IF e IS FolderElem THEN d.MoveDir(p(FolderElem), elem(FolderElem), e(FolderElem),srcDev) ELSE d.Move(p(FolderElem), elem(FolderElem), e, srcDev) END END END; Kernel.GC; COPY(srcParent(FolderElem).dir.path, fullName); d.Append(fullName, elem.name); Directories.Delete(fullName); d.done := Directories.res = noErr END END ELSE END; IF ~d.done THEN LogString(elem.name); LogString(" moving failded"); LogLn END END MoveDir;  PROCEDURE (d: Device) MoveToTrash* (parent: FMElems.FolderElem; elem: FMElems.Elem); VAR e: FMElems.Elem; path: FMDevObj.Path; BEGIN d.done := TRUE; WITH parent: FolderElem DO elem := d.GetElem(parent, elem.name); IF elem # NIL THEN d.GetPath(parent, path); IF (trashE # NIL) & (trashPath # path) THEN e := d.GetElem(trashE, elem.name); IF e # NIL THEN d.Delete(trashE, e); IF ~d.done THEN RETURN END END; IF elem IS FolderElem THEN d.MoveDir(trashE, parent, elem(FolderElem), d) ELSE d.Move(trashE, parent, elem, d) END ELSE d.Delete(parent, elem) END END ELSE END END MoveToTrash;  PROCEDURE NewDevObj* (fullName: ARRAY OF CHAR; VAR folder: FMElems.FolderElem; VAR attributes: FMElems.Attributes; sortOrder: ARRAY OF CHAR): Device; VAR d: Device; dir: Directories.Directory; name, pattern, pat: FMElems.Name; path: FMDevObj.Path; f: FolderElem; i, j, k: INTEGER; BEGIN i := 0; j := 0; WHILE fullName[i] # 0X DO IF (fullName[i] = Directories.delimiter) OR (fullName[i] = "$") THEN j := i + 1 END; INC(i) END; FOR k := 0 TO i - j DO pattern[k] := fullName[j + k] END; IF pattern[0] = 0X THEN pattern := "*" END; IF j = 0 THEN dir := Directories.Current() ELSE fullName[j] := 0X;dir := Directories.This(fullName) END; IF dir # NIL THEN NEW(d); d.delimiter := Directories.delimiter; i := 0; j := 0; WHILE dir.path[i] # 0X DO IF (dir.path[i] = d.delimiter) & (dir.path[i+1] # 0X) THEN j := i + 1 END; INC(i) END; FOR k := 0 TO i - j DO name[k] := dir.path[j+k] END; IF ((i-j) > 0) & (name[i-j-1] = d.delimiter) THEN name[i-j-1] := 0X END; NEW(f); InitFolderElem(f, name, pattern, sortOrder, attributes, FALSE, dir); folder := f; RETURN d END; RETURN NIL END NewDevObj;  PROCEDURE Notify (op: INTEGER; path, name: ARRAY OF CHAR); (* delete op = 0, insert op = 1 *) VAR msg: FMDevObj.NotifyMsg; d: Device; BEGIN IF op <= 1 THEN NEW(d); d.delimiter := Directories.delimiter; msg.devObj := d; msg.id := op; COPY(path, msg.path); Strings.Cap(msg.path); COPY(name, msg.name); Viewers.Broadcast(msg) END; oldNotifier(op, path, name) END Notify;  PROCEDURE SearchSection (T: Texts.Text; VAR S: Texts.Scanner; name: ARRAY OF CHAR): BOOLEAN; BEGIN Texts.OpenScanner(S, T, 0); REPEAT Texts.Scan(S) UNTIL S.eot OR ((S.class = Texts.Char) & (S.c = "[")); REPEAT Texts.Scan(S) UNTIL S.eot OR ((S.class = Texts.Name) & (S.s = name) & (S.nextCh = "]")); RETURN ~S.eot END SearchSection;  PROCEDURE InitTrash; VAR attributes: FMElems.Attributes; S: Texts.Scanner; fullPath, path: FMDevObj.Path; name, pattern: FMElems.Name; dir: Directories.Directory; i, j, k: INTEGER; BEGIN trashE := NIL; IF SearchSection(TextFrames.Text(ConfigurationFile), S, "Trash") THEN REPEAT Texts.Scan(S) UNTIL S.eot OR ((S.class = Texts.Name) & (S.s = "Trash")); REPEAT Texts.Scan(S) UNTIL S.eot OR ((S.class = Texts.Char) & (S.c = "=")); REPEAT Texts.Scan(S) UNTIL S.eot OR (S.class = Texts.String); IF S.class = Texts.String THEN COPY(S.s, path) END; IF path[0] # 0X THEN dir := Directories.This(path); IF dir = NIL THEN Directories.Create(path); IF Directories.res # noErr THEN LogString("can not create trash "); LogLn; RETURN END; dir := Directories.This(path) END; IF dir # NIL THEN i := 0; j := 0; WHILE dir.path[i] # 0X DO IF (dir.path[i] = Directories.delimiter) & (dir.path[i+1] # 0X) THEN j := i + 1 END; INC(i) END; FOR k := 0 TO i - j DO name[k] := dir.path[j + k] END; attributes.nOfAttributes := 0; NEW(trashE); InitFolderElem(trashE, name, pattern, FMDevObj.sortName, attributes, FALSE, dir); COPY(dir.path, trashPath); Strings.Cap(trashPath) END ELSE LogString(" no trash specified "); LogLn END END END InitTrash;  PROCEDURE InitApplicationList(VAR list: Node); VAR patterns: ARRAY 20 OF Pattern; i: INTEGER; S: Texts.Scanner; node: Node; last: Node; line: INTEGER; BEGIN list := NIL; IF SearchSection(TextFrames.Text(ConfigurationFile), S, "Application") THEN i := 0; Texts.Scan(S); WHILE ~S.eot & ~((S.class = Texts.Char) & (S.c = "[")) DO IF S.class = Texts.String THEN IF i < 20 THEN COPY(S.s, patterns[i]); INC(i) END; Texts.Scan(S) ELSIF (S.class = Texts.Char) & (S.c = "=") THEN REPEAT Texts.Scan(S) UNTIL S.eot OR (S.class = Texts.String); IF S.class = Texts.String THEN NEW(node); node.next := NIL; node.withPath := FALSE; COPY(S.s, node.cmd); NEW(node.patterns, i); WHILE i > 0 DO DEC(i); COPY(patterns[i], node.patterns[i]) END; line := S.line; REPEAT Texts.Scan(S) UNTIL S.eot OR ((S.class = Texts.Char) & (S.c = "/" )) OR (S.line > line); IF ~S.eot & (S.class = Texts.Char) & (S.c = "/" ) & (S.nextCh = "p") THEN node.withPath := TRUE END; IF list = NIL THEN list := node; last := node ELSE last.next := node; last := node END ELSE i := 0 END ELSE Texts.Scan(S) END END END END InitApplicationList;  BEGIN Texts.OpenWriter(w); oldNotifier := Directories.notify; Directories.notify := Notify; NEW(buf, BufSize); InitTrash; InitApplicationList(applicationList) END FMSysDevObj.