Syntax10.Scn.Fnt8InfoElemsAllocUSyntax10.Scn.FntzStampElemsAlloc1 Sep 97s"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 28 Aug 97, claudio, quickly hacked up to work on SGI. "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. 0 IiParcElemsAlloc Hh٢S8FoldElemsNew,88X83MarkElemsAlloc8K818,88n8288488$8.8+88 σ>8k8 @88+88+`8#Syntax10.Scn.Fnt~~ VAR absPath: ARRAY 128 OF CHAR; dirName: ARRAY 32 OF CHAR; BEGIN ExpandPath(path, absPath); IF Rmdir(SYSTEM.ADR(absPath)) = 0 THEN Split(absPath, path, dirName); notify(delete, path, dirName); res := noErr ELSE CASE res OF ENAMETOOLONG: res := badName | ENOTDIR: res := notADir | ENOTEMPTY, EBUSY: res := dirInUse ELSE res := otherError END END END Delete; 878#Syntax10.Scn.Fnt 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 UnixRename(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 EBUSY: res := alreadyExists | ENAMETOOLONG: res := badName | ENOENT: res := notADir ELSE res := otherError END END END (* VAR i: LONGINT; BEGIN i := Unix.Rename(SYSTEM.ADR(oldPath), SYSTEM.ADR(newPath)) *) END Rename; 878#Syntax10.Scn.FntNN CONST nameLength=64; TYPE Sort = POINTER TO SortDesc; SortDesc = RECORD name: ARRAY nameLength+2 OF CHAR; next: Sort END; VAR dir: Dir; entry: DirEntry; compFile: ARRAY 1024 OF CHAR; cont: BOOLEAN; cur, prev, next, list: Sort; 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[nameLength] := 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; closedir(dir); cur := list; WHILE (cur # NIL) & cont DO proc(d, cur.name, IsDir(cur.name), cont); cur := cur.next END END Enumerate; 8.18#Syntax10.Scn.Fnt 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; 8?8#Syntax10.Scn.Fnt END NoNotify; 88#Syntax10.Scn.Fnt77 notify := NoNotify; libc:=Unix.dlopen("libc.so",Unix.rtldNow); Unix.dlsym(libc, "getcwd", SYSTEM.VAL(LONGINT, getcwd)); Unix.dlsym(libc, "opendir", SYSTEM.VAL(LONGINT, opendir)); Unix.dlsym(libc, "readdir", SYSTEM.VAL(LONGINT, readdir)); Unix.dlsym(libc, "closedir", SYSTEM.VAL(LONGINT, closedir)); Init8MODULE Directories;  IMPORT Console, SYSTEM, Kernel, Unix; 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 **) ENOENT=2; EBUSY=16; EEXIST=17; ENOTDIR=20; ENAMETOOLONG=78; ENOTEMPTY=93; 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); (* Linux System stuff *) EnvVar = POINTER TO ARRAY 1024 OF CHAR; Dir = SYSTEM.PTR; DirEntry = POINTER TO DirEntryDesc; DirEntryDesc = RECORD fileno: LONGINT; rec: LONGINT; nameLen: INTEGER; name: ARRAY 256 OF CHAR END;  VAR res*: INTEGER; notify*: Notifier; libc:LONGINT; startupPath: ARRAY 256 OF CHAR; (*path containing the Oberon application*) paths: SearchPath; getcwd: PROCEDURE (VAR CWD: ARRAY OF CHAR); opendir: PROCEDURE (path: LONGINT): Dir; readdir: PROCEDURE (dir: Dir): DirEntry; closedir: PROCEDURE (dir: Dir); PROCEDURE -UnixRename (from, to: LONGINT):LONGINT 90, 4, 2, 52, 12, 0, 0, 0; PROCEDURE -Rmdir (pathadr: LONGINT):LONGINT 55, 4, 2, 52, 12, 0, 0, 0; PROCEDURE -Mkdir (pathadr: LONGINT; mode: SET):LONGINT 56, 4, 2, 52, 12, 0, 0, 0; PROCEDURE Current* (): Directory;  VAR d: Directory; BEGIN NEW(d); getcwd(d.path); 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 Init;  VAR d: Directory; i, j, len: INTEGER; path: ARRAY 256 OF CHAR; p: SearchPath; o: ARRAY 1024 OF CHAR; ch: CHAR; var: EnvVar; BEGIN d := Current(); COPY(d.path, startupPath); Unix.dlsym(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) ELSE 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; NEW(p); NEW(p.dir); COPY(path, p.dir.path); p.next := paths; paths := p END Init;  PROCEDURE IsDir (path: ARRAY OF CHAR): BOOLEAN;  VAR i: LONGINT; statbuf: Unix.Status; done:BOOLEAN; BEGIN Unix.Stat(SYSTEM.ADR(path), statbuf); done:=Unix.Done(); i := statbuf.mode; RETURN SYSTEM.VAL(SET,i) * {12..15}={14}; END IsDir;  PROCEDURE This* (path: ARRAY OF CHAR): Directory;  VAR d: Directory; BEGIN IF IsDir(path) THEN NEW(d); COPY(path, d.path); res := noErr; RETURN d ELSE res := notADir; RETURN NIL END END This;  PROCEDURE Startup* (): Directory;  BEGIN RETURN This(startupPath) END Startup;  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); Console.Ln; CASE res OF ENAMETOOLONG: res := badName | ENOTDIR: res := notADir ELSE res := otherError END END END Change;  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 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(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 EEXIST: res := alreadyExists | ENAMETOOLONG: res := badName ELSE res := otherError END END END Create;  PROCEDURE Delete* (path: ARRAY OF CHAR);  PROCEDURE Rename* (oldPath, newPath: ARRAY OF CHAR);  PROCEDURE Enumerate* (d: Directory; proc: FileProc);  PROCEDURE EnumeratePaths* (proc: PathProc);  PROCEDURE NoNotify (op: INTEGER; path, name: ARRAY OF CHAR);  BEGIN END Directories.