Syntax10.Scn.FntInfoElemsAllocTSyntax10.Scn.FntzStampElemsAlloc7 Aug 25"Title": Directories for Oberon for Linux "Author": Robert Lichtenberger "Abstract": Provide multiple directory access "Keywords": System Directory "Version": 2.0 "From": 3 Sep 96 "Until":  "Changes": 6 Oct 96, RLI, Removed the Strings-Module Import in order to include Directories into the BootLink file 8 Oct 96, RLI, Truncated filenames to 32 Char in order to prevent crashes of Files.Rename 12 Sep 97, RLI, This(...) now accepts Paths beginning with $ 16 Feb 98, RLI, Fixed Enumerate 25 Feb 98, RLI, Enlarged EnvVar to 4096 25 May 98, RLI, Added closedir to Enumerate "Hints": Edit.Open Directories.Text "Notes": Unlike the Windows-Version this version enumerates Files in alphabetical order. I found that convenient when searching for files. Syntax10i.Scn.Fnt/ IiParcElemsAlloc Syntax10b.Scn.Fnt    "&    Z   Z ~8FoldElemsNew,8 9 .*MarkElemsAlloc8818,8 888P8 σ>8k8 @88288 #88 8.8 88 88 $8`X= 8  !8"8 88?88828%MODULE Directories;  IMPORT SYSTEM, Kernel, Unix, Console; CONST  noErr* = 0; (**no error*) badName* = 1; (**bad file or directory name*) mediumFull* = 2; (**disk or directory full*) mediumLocked* = 3; (**hardware or software lock*) dirInUse* = 4; (**directory in use or not empty*) notADir* = 5; (**name does not specify a directory*) alreadyExists* = 6; (**directory already exists*) otherError* = 7; (**other OS-specific error*) delete* = 0; insert* = 1; change* = 2; (** notify operations **) delimiter* = "/"; (** delimiter in path names **) EnvVarLen = 4096; TYPE Directory* = POINTER TO DirectoryDesc; DirectoryDesc* = RECORD path*: ARRAY 256 OF CHAR END; FileProc* = PROCEDURE (d: Directory; name: ARRAY OF CHAR; isDir: BOOLEAN; VAR continue: BOOLEAN); PathProc* = PROCEDURE (path: ARRAY OF CHAR; VAR continue: BOOLEAN); SearchPath = POINTER TO SearchPathDesc; SearchPathDesc = RECORD  dir: Directory; next: SearchPath END;  Notifier* = PROCEDURE (op: INTEGER; path, name: ARRAY OF CHAR); (* Solaris System stuff *) SolarisDirent = RECORD ino, off: LONGINT; reclen: INTEGER; name: ARRAY 256 OF CHAR; END ; EnvVar = POINTER TO ARRAY EnvVarLen OF CHAR; Dir = SYSTEM.PTR; DirEntry = POINTER TO SolarisDirent; VAR res*: INTEGER; notify*: Notifier; startupPath: ARRAY 256 OF CHAR; (*path containing the Oberon application*) paths: SearchPath; getcwd: PROCEDURE (cwdAdr: LONGINT; len: LONGINT): LONGINT; opendir: PROCEDURE (path: LONGINT): Dir; closedir: PROCEDURE (dir: Dir): INTEGER; readdir: PROCEDURE (dir: Dir): DirEntry; PROCEDURE Current* (): Directory;  VAR d: Directory; x: LONGINT; BEGIN NEW(d); x := getcwd(SYSTEM.ADR(d.path), LEN(d.path)); IF x = 0 THEN Console.Str("Directories: Could not get current working directory, Unix.errno is "); Console.Int(Unix.Errno(), 2); Console.Ln; END; RETURN d END Current;  PROCEDURE Extend (VAR s, path: ARRAY OF CHAR);  VAR i, j: INTEGER; n: ARRAY 128 OF CHAR; d: Directory; BEGIN IF s[0] = "$" THEN COPY(startupPath, path); i := 0; WHILE path[i] # 0X DO INC(i) END; path[i] := delimiter; j := 1; WHILE s[j] # 0X DO path[i + j] := s[j]; INC(j) END; path[i+j] := 0X; ELSE COPY(s, path); END END Extend;  PROCEDURE Change* (path: ARRAY OF CHAR);  VAR extPath: ARRAY 1024 OF CHAR; BEGIN Extend(path, extPath); res := SHORT(Unix.Chdir(SYSTEM.ADR(extPath))); IF res = 0 THEN notify (change, "", "") ELSE Console.Str("Cannot change into "); Console.Str(extPath); Console.Str(" unix errcode = "); Console.Int(res, 2); Console.Ln; CASE res OF Unix.ENAMETOOLONG: res := badName | Unix.ENOTDIR: res := notADir ELSE res := otherError END END END Change;  PROCEDURE Init;  VAR d: Directory; i, j, len: INTEGER; path: ARRAY 256 OF CHAR; p: SearchPath; o: ARRAY EnvVarLen OF CHAR; ch: CHAR; var: EnvVar; BEGIN d := Current(); COPY(d.path, startupPath); Kernel.dlsym(Kernel.libc, "OBERON", SYSTEM.VAL(LONGINT, var)); IF var = NIL THEN o := ". /usr/local/Oberon /usr/local/Oberon/.Fonts" ELSE i := 0; REPEAT ch := var^[i]; IF ch = ":" THEN ch := " " END; o[i] := ch; INC(i) UNTIL ch = 0X END; (* Get all directories that must be searched when an open command is launched *) j := 0; paths := NIL; len := 0; WHILE o[len] # 0X DO INC(len) END; FOR i := 0 TO len - 1 DO IF o[i] # ' ' THEN path[j] := o[i]; INC(j) ELSIF j > 0 THEN path[j] := 0X; j := 0; NEW(p); NEW(p.dir); COPY(path, p.dir.path); p.next := paths; paths := p END END; path[j] := 0X; IF j > 0 THEN NEW(p); NEW(p.dir); COPY(path, p.dir.path); p.next := paths; paths := p END; END Init;  PROCEDURE ExpandPath (this: ARRAY OF CHAR; VAR absPath: ARRAY OF CHAR);  VAR done: BOOLEAN; current: ARRAY 128 OF CHAR; i, j: INTEGER; d: Directory; BEGIN NEW(d); d := Current(); COPY(d.path, current); IF this[0] = "$" THEN COPY(startupPath, absPath); i := 0; WHILE absPath[i] # 0X DO INC(i) END ; IF this[1] # delimiter THEN absPath[i] := delimiter; INC(i) END ; j := 1; WHILE this[j] # 0X DO absPath[i] := this[j]; INC(i); INC(j) END ; absPath[i] := 0X ELSE COPY(this, absPath) END ; Change(absPath); done := res = noErr; IF done THEN NEW(d); d := Current(); COPY(d.path, absPath); Change(current); done := res = noErr ELSE absPath[0] := 0X END END ExpandPath;  PROCEDURE Split (path: ARRAY OF CHAR; VAR path0, dirName: ARRAY OF CHAR);  VAR i, j: INTEGER; BEGIN i := 0; j := 0; WHILE path[i] # 0X DO path0[i] := path[i]; IF path[i] = delimiter THEN j := i END ; INC(i) END ; path0[j] := 0X; INC(j); i := 0; WHILE path[j] # 0X DO dirName[i] := path[j]; INC(i); INC(j) END ; dirName[i] := 0X END Split;  PROCEDURE IsDir (path: ARRAY OF CHAR): BOOLEAN;  VAR i, j: LONGINT; statbuf: Unix.Status; BEGIN i := Unix.Stat(SYSTEM.ADR(path), SYSTEM.ADR(statbuf)); i := statbuf.mode; j := 61440; IF SYSTEM.VAL(SET, i) * SYSTEM.VAL(SET, j) = {14} THEN RETURN TRUE ELSE RETURN FALSE END END IsDir;  PROCEDURE This* (path: ARRAY OF CHAR): Directory;  VAR d: Directory; absPath: ARRAY 512 OF CHAR; BEGIN IF path = "" THEN RETURN NIL END; Extend(path, absPath); IF IsDir(absPath) THEN NEW(d); COPY(absPath, d.path); res := noErr; RETURN d ELSE res := notADir; RETURN NIL END; END This;  PROCEDURE Startup* (): Directory;  BEGIN RETURN This(startupPath) END Startup;  PROCEDURE Create* (path: ARRAY OF CHAR);  VAR absPath: ARRAY 128 OF CHAR; dirName: ARRAY 32 OF CHAR; i, j: INTEGER; BEGIN IF path[0] = "$" THEN COPY(startupPath, absPath); i := 0; WHILE absPath[i] # 0X DO INC(i) END ; IF path[1] # delimiter THEN absPath[i] := delimiter; INC(i) END ; j := 1; WHILE path[j] # 0X DO absPath[i] := path[j]; INC(i); INC(j) END ; absPath[i] := 0X ELSE COPY(path, absPath) END ; res := SHORT(Unix.Mkdir(SYSTEM.ADR(absPath), {MIN(SET)..MAX(SET)})); IF res = 0 THEN ExpandPath(absPath, absPath); Split(absPath, path, dirName); notify(insert, path, dirName); res := noErr ELSE CASE res OF Unix.EEXIST: res := alreadyExists | Unix.ENAMETOOLONG: res := badName ELSE res := otherError END END END Create;  PROCEDURE Delete* (path: ARRAY OF CHAR);  VAR absPath: ARRAY 128 OF CHAR; dirName: ARRAY 32 OF CHAR; BEGIN ExpandPath(path, absPath); IF Unix.Rmdir(absPath) = 0 THEN Split(absPath, path, dirName); notify(delete, path, dirName); res := noErr ELSE CASE res OF Unix.ENAMETOOLONG: res := badName | Unix.ENOTDIR: res := notADir | Unix.ENOTEMPTY, Unix.EBUSY: res := dirInUse ELSE res := otherError END END END Delete;  PROCEDURE Rename* (oldPath, newPath: ARRAY OF CHAR);  VAR oldPath0, newPath0: ARRAY 128 OF CHAR; oldName, newName: ARRAY 32 OF CHAR; i, j: INTEGER; BEGIN res := otherError; ExpandPath(oldPath, oldPath0); IF oldPath0[0] # 0X THEN IF newPath[0] = "$" THEN COPY(startupPath, newPath0); i := 0; WHILE newPath0[i] # 0X DO INC(i) END ; IF newPath[1] # delimiter THEN newPath0[i] := delimiter; INC(i) END ; j := 1; WHILE newPath[j] # 0X DO newPath0[i] := newPath[j]; INC(i); INC(j) END ; newPath0[i] := 0X ELSE COPY(newPath, newPath0) END ; IF Unix.Rename(SYSTEM.ADR(oldPath0), SYSTEM.ADR(newPath0)) = 0 THEN Split(oldPath0, oldPath, oldName); notify(delete, oldPath, oldName); ExpandPath(newPath0, newPath0); Split(newPath0, newPath, newName); notify(insert, newPath, newName); res := noErr ELSE CASE res OF Unix.EBUSY: res := alreadyExists | Unix.ENAMETOOLONG: res := badName | Unix.ENOENT: res := notADir ELSE res := otherError END END END (* VAR i: LONGINT; BEGIN i := Unix.Rename(SYSTEM.ADR(oldPath), SYSTEM.ADR(newPath)) *) END Rename;  PROCEDURE Enumerate* (d: Directory; proc: FileProc);  TYPE Sort = POINTER TO SortDesc; SortDesc = RECORD name: ARRAY 32 OF CHAR; next: Sort END; VAR dir: Dir; entry: DirEntry; fullName: ARRAY 1024 OF CHAR; cont: BOOLEAN; cur, prev, next, list: Sort; i, len: INTEGER; BEGIN dir := NIL; cont := TRUE; list := NIL; dir := opendir(SYSTEM.ADR(d.path)); entry := readdir(dir); WHILE (entry # NIL) DO NEW(cur); COPY(entry.name, cur.name); cur.name[31] := 0X; next := list; prev := NIL; WHILE (next # NIL) & (next.name < entry.name) DO prev := next; next := next.next END; IF prev = NIL THEN cur.next := list; list := cur ELSE cur.next := next; prev.next := cur END; entry := readdir(dir) END; cur := list; COPY(d.path, fullName); i := 0; WHILE fullName[i] # 0X DO INC(i) END; fullName[i] := '/'; INC(i); len := i; WHILE (cur # NIL) & cont DO i := 0; WHILE cur.name[i] # 0X DO fullName[len+i] := cur.name[i]; INC(i) END; fullName[len+i] := 0X; proc(d, cur.name, IsDir(fullName), cont); cur := cur.next END; ASSERT(closedir(dir) = 0); END Enumerate;  PROCEDURE EnumeratePaths* (proc: PathProc);  VAR cur: SearchPath; cont: BOOLEAN; BEGIN cur := paths; cont := TRUE; WHILE (cur # NIL) & cont DO proc(cur.dir.path, cont); cur := cur.next END END EnumeratePaths;  PROCEDURE NoNotify (op: INTEGER; path, name: ARRAY OF CHAR);  END NoNotify;  BEGIN notify := NoNotify; Kernel.dlsym(Kernel.libc, "getcwd", SYSTEM.VAL(LONGINT, getcwd)); Kernel.dlsym(Kernel.libc, "opendir", SYSTEM.VAL(LONGINT, opendir)); Kernel.dlsym(Kernel.libc, "closedir", SYSTEM.VAL(LONGINT, closedir)); Kernel.dlsym(Kernel.libc, "readdir", SYSTEM.VAL(LONGINT, readdir)); Init;  END Directories.