Alexander Shiryaev преди 12 години
родител
ревизия
e46bcc02f6
променени са 62 файла, в които са добавени 4125 реда и са изтрити 53 реда
  1. 0 1
      BlackBox/BlackBox
  2. 0 1
      BlackBox/BlackBox-dl
  3. 1 0
      BlackBox/Linux/BlackBox
  4. BIN
      BlackBox/Linux/Lin/Mod/Console.odc
  5. 113 0
      BlackBox/Linux/Lin/Mod/Console.txt
  6. BIN
      BlackBox/Linux/Lin/Mod/Dates.odc
  7. 92 0
      BlackBox/Linux/Lin/Mod/Dates.txt
  8. BIN
      BlackBox/Linux/Lin/Mod/Dl.odc
  9. 30 0
      BlackBox/Linux/Lin/Mod/Dl.txt
  10. BIN
      BlackBox/Linux/Lin/Mod/Kernel.odc
  11. 1991 0
      BlackBox/Linux/Lin/Mod/Kernel.txt
  12. 0 0
      BlackBox/Linux/Lin/Mod/Kernel_so_init.odc
  13. 0 0
      BlackBox/Linux/Lin/Mod/Kernel_so_init.txt
  14. BIN
      BlackBox/Linux/Lin/Mod/Libc.odc
  15. 452 0
      BlackBox/Linux/Lin/Mod/Libc.txt
  16. BIN
      BlackBox/Linux/Lin/Mod/linHostFiles.odc
  17. 1304 0
      BlackBox/Linux/Lin/Mod/linHostFiles.txt
  18. 1 0
      BlackBox/Linux/Lin/Rsrc/loader/BlackBox-dl.c
  19. 1 0
      BlackBox/Linux/Lin/Rsrc/loader/BlackBox.c
  20. 1 0
      BlackBox/Linux/Lin/Rsrc/loader/BlackBox1.c
  21. 21 0
      BlackBox/Linux/Lin/Rsrc/loader/Makefile
  22. 1 0
      BlackBox/Linux/Lin/Rsrc/loader/libBB.so
  23. 1 0
      BlackBox/Linux/Lin/Rsrc/loader/libBB0.so
  24. BIN
      BlackBox/Linux/libBB.so
  25. BIN
      BlackBox/Linux/libBB0.so
  26. 1 0
      BlackBox/Linux/lindev
  27. 1 0
      BlackBox/OpenBSD/BlackBox
  28. 0 0
      BlackBox/OpenBSD/Lin/Mod/Console.odc
  29. 1 1
      BlackBox/OpenBSD/Lin/Mod/Console.txt
  30. 0 0
      BlackBox/OpenBSD/Lin/Mod/Dates.odc
  31. 1 1
      BlackBox/OpenBSD/Lin/Mod/Dates.txt
  32. 0 0
      BlackBox/OpenBSD/Lin/Mod/Dl.txt
  33. 0 0
      BlackBox/OpenBSD/Lin/Mod/Kernel.odc
  34. 1 1
      BlackBox/OpenBSD/Lin/Mod/Kernel.txt
  35. 1 0
      BlackBox/OpenBSD/Lin/Mod/Kernel_so_init.odc
  36. 1 0
      BlackBox/OpenBSD/Lin/Mod/Kernel_so_init.txt
  37. 0 0
      BlackBox/OpenBSD/Lin/Mod/Libc.txt
  38. 0 0
      BlackBox/OpenBSD/Lin/Mod/linHostFiles.odc
  39. 1 1
      BlackBox/OpenBSD/Lin/Mod/linHostFiles.txt
  40. 0 0
      BlackBox/OpenBSD/Lin/Rsrc/loader/BlackBox-dl.c
  41. 0 0
      BlackBox/OpenBSD/Lin/Rsrc/loader/BlackBox.c
  42. 0 0
      BlackBox/OpenBSD/Lin/Rsrc/loader/BlackBox1.c
  43. 12 4
      BlackBox/OpenBSD/Lin/Rsrc/loader/Makefile
  44. 1 0
      BlackBox/OpenBSD/Lin/Rsrc/loader/libBB.so
  45. 1 0
      BlackBox/OpenBSD/Lin/Rsrc/loader/libBB0.so
  46. 0 0
      BlackBox/OpenBSD/Lin/Rsrc/loader/libdlobsdwrap.c
  47. 0 0
      BlackBox/OpenBSD/libBB.so
  48. 0 0
      BlackBox/OpenBSD/libBB0.so
  49. 1 0
      BlackBox/OpenBSD/libdlobsdwrap.so
  50. 1 0
      BlackBox/OpenBSD/lindev
  51. 6 6
      BlackBox/build
  52. 5 5
      BlackBox/build-lindev
  53. 0 1
      BlackBox/libdlobsdwrap.so
  54. 0 1
      BlackBox/lindev
  55. 0 12
      BlackBox/run-BlackBox-dl
  56. 0 1
      BlackBox/run-lindev
  57. 4 0
      BlackBox/run-lindev
  58. 49 0
      BlackBox/switch-os
  59. 28 11
      README
  60. 0 1
      c/libBB.so
  61. 0 1
      c/libBB0.so
  62. 0 4
      c/run-lindev

+ 0 - 1
BlackBox/BlackBox

@@ -1 +0,0 @@
-../c/BlackBox

+ 0 - 1
BlackBox/BlackBox-dl

@@ -1 +0,0 @@
-../c/BlackBox-dl

+ 1 - 0
BlackBox/Linux/BlackBox

@@ -0,0 +1 @@
+Lin/Rsrc/loader/BlackBox

BIN
BlackBox/Linux/Lin/Mod/Console.odc


+ 113 - 0
BlackBox/Linux/Lin/Mod/Console.txt

@@ -0,0 +1,113 @@
+MODULE LinConsole;
+
+	(* THIS IS TEXT COPY OF OpenBUGS Lin/Mod/Console.odc *)
+	(* DO NOT EDIT *)
+
+	IMPORT
+		SYSTEM,
+		Console,
+		LinLibc;
+
+	TYPE
+		LinCons = POINTER TO RECORD (Console.Console) END;
+
+		LinProcess = POINTER TO RECORD (Console.Process) END;
+
+	CONST
+		strLen = 1024;
+
+	VAR
+		s: ARRAY strLen OF CHAR;
+		ss: ARRAY strLen OF SHORTCHAR;
+		linCons: LinCons;
+		version-: INTEGER;
+		maintainer-: ARRAY 40 OF CHAR;
+
+	PROCEDURE (cons: LinCons) ReadLn (OUT text: ARRAY OF CHAR);
+		VAR
+			i: INTEGER;
+			str: POINTER TO ARRAY [untagged] OF SHORTCHAR; 
+	BEGIN
+		str := LinLibc.fgets(ss, strLen, LinLibc.stdin);
+		IF (str = NIL) THEN 
+			(* if end of file, then ss is not changed by fgets and NIL is returned. 
+			    We return an empty string here *)
+			text[0] := 0X;
+			RETURN
+		END;			
+		i := 0;
+		REPEAT
+			text[i] := ss[i];
+			INC(i)
+		UNTIL (ss[i] = 0X) OR (i = LEN(text) - 1);
+		text[i] := 0X 
+	END ReadLn;
+
+	PROCEDURE Printf;
+		VAR res: INTEGER;
+	BEGIN
+		res := LinLibc.printf(ss);
+		res := LinLibc.fflush(LinLibc.NULL)
+	END Printf;
+
+	PROCEDURE (cons: LinCons) WriteChar (c: CHAR);
+	BEGIN
+		s[0] := c;
+		s[1] := 0X;
+		ss := SHORT(s);
+		Printf()
+	END WriteChar;
+
+	PROCEDURE (cons: LinCons) WriteStr (IN text: ARRAY OF CHAR);
+	BEGIN
+		ss := SHORT(text);
+		Printf()
+	END WriteStr;
+
+	PROCEDURE (cons: LinCons) WriteLn;
+	BEGIN
+		ss[0] := 0AX;
+		ss[1] := 0X;
+		Printf()
+	END WriteLn;
+
+	PROCEDURE (cons: LinCons) Open;
+	BEGIN
+	END Open;
+
+	PROCEDURE (cons: LinCons) Close;
+	BEGIN
+	END Close;
+
+	PROCEDURE (cons: LinCons) CreateProcess (cmdLine: ARRAY OF CHAR): Console.Process;
+	BEGIN
+		(*	needs coding	*)
+		RETURN NIL
+	END CreateProcess;
+
+	PROCEDURE (cons: LinCons) CommandLine (OUT cmdLine: ARRAY OF CHAR);
+	BEGIN
+
+	END CommandLine;
+
+	PROCEDURE (p: LinProcess) Terminate;
+	BEGIN
+		(*	needs coding	*)
+	END Terminate;
+
+	PROCEDURE Maintainer;
+	BEGIN
+		version := 303;
+		maintainer := "A.Thomas"
+	END Maintainer;
+
+	PROCEDURE Init;
+	BEGIN
+		Maintainer;
+		NEW(linCons);
+		Console.SetConsole(linCons)
+	END Init;
+
+BEGIN
+	Init
+END LinConsole.

BIN
BlackBox/Linux/Lin/Mod/Dates.odc


+ 92 - 0
BlackBox/Linux/Lin/Mod/Dates.txt

@@ -0,0 +1,92 @@
+MODULE HostDates;
+
+	(* THIS IS TEXT COPY OF Dates.odc *)
+	(* DO NOT EDIT *)
+
+	IMPORT 
+		SYSTEM, LinLibc, Dates;
+	
+	(* Dates Hook *)
+	
+		TYPE
+		DatesHook = POINTER TO RECORD (Dates.Hook) END;
+	
+	(*
+	
+	Some conversions are needed between the Linux and the BlackBox representations of  dates. The following
+	table shows the differences:
+	
+(!)		Linux	BlackBox
+	year	from year 1900	from year 0000
+	month	range 0-11	range 1-12
+	weekday	0:sunday - 6:satruday	0:monday - 6:sunday
+	(!)	*)
+	
+	PROCEDURE (h: DatesHook) DateToString (d: Dates.Date; format: INTEGER; OUT str: ARRAY OF CHAR);
+		VAR tm: LinLibc.tmDesc; sstr: ARRAY 64 OF SHORTCHAR; res: LinLibc.size_t; 
+	BEGIN
+		ASSERT(format IN {Dates.short, Dates.abbreviated, Dates.long, Dates.plainAbbreviated, Dates.plainLong}, 20);
+		tm.tm_year := d.year - 1900; (* Linux counts years from 1900 but BlackBox from 0000 *)
+		tm.tm_mon := d.month - 1; tm.tm_mday := d.day;
+		tm.tm_wday := (Dates.DayOfWeek(d) + 1) MOD 7;		
+		IF format = Dates.short THEN
+			res := LinLibc.strftime(sstr, LEN(sstr), "%x", SYSTEM.VAL(LinLibc.tm, SYSTEM.ADR(tm)))
+		ELSIF format = Dates.abbreviated THEN
+			res := LinLibc.strftime(sstr, LEN(sstr), "%a, %b %d, %Y", SYSTEM.VAL(LinLibc.tm, SYSTEM.ADR(tm)))
+		ELSIF format = Dates.long THEN
+			res := LinLibc.strftime(sstr, LEN(sstr), "%A, %B %d, %Y", SYSTEM.VAL(LinLibc.tm, SYSTEM.ADR(tm)))
+		ELSIF format = Dates.plainAbbreviated THEN
+			res := LinLibc.strftime(sstr, LEN(sstr), "%b %d, %Y", SYSTEM.VAL(LinLibc.tm, SYSTEM.ADR(tm)))
+		ELSE (* format = Dates.plainLong *)
+			res := LinLibc.strftime(sstr, LEN(sstr), "%B %d, %Y", SYSTEM.VAL(LinLibc.tm, SYSTEM.ADR(tm)))
+		END;
+		IF res > 0 THEN str := sstr$ELSE str := "invalid date"  END
+	END DateToString;
+
+	PROCEDURE (h: DatesHook) GetTime (OUT d: Dates.Date; OUT t: Dates.Time);
+		VAR time: LinLibc.time_t; tm: LinLibc.tm;
+	BEGIN
+		time := LinLibc.time(NIL);
+		tm := LinLibc.localtime(time);
+		d.year := tm.tm_year + 1900; (* Linux counts years from 1900 but BlackBox from 0000 *)
+		d.month := tm.tm_mon + 1;  d.day := tm.tm_mday;
+		t.hour := tm.tm_hour; t.minute := tm.tm_min; t.second := tm.tm_sec
+	END GetTime;
+
+	PROCEDURE (h: DatesHook) GetUTCBias (OUT bias: INTEGER);
+		VAR time: LinLibc.time_t; tm: LinLibc.tm;
+	BEGIN
+		time := LinLibc.time(NIL);
+		tm := LinLibc.localtime(time); (* call to localtime needed to make sure that timezone is set *)
+		bias := LinLibc.timezone DIV 60;
+	END GetUTCBias; 
+
+	PROCEDURE (h: DatesHook) GetUTCTime (OUT d: Dates.Date; OUT t: Dates.Time);
+		VAR time: LinLibc.time_t; tm: LinLibc.tm;
+	BEGIN
+		time := LinLibc.time(NIL);
+		tm := LinLibc.gmtime(time);
+		d.year := tm.tm_year + 1900; (* Linux counts years from 1900 but BlackBox from 0000 *)
+		d.month := tm.tm_mon + 1;  d.day := tm.tm_mday;
+		t.hour := tm.tm_hour; t.minute := tm.tm_min; t.second := tm.tm_sec
+	END GetUTCTime;
+
+	PROCEDURE (h: DatesHook) TimeToString (t: Dates.Time; OUT str: ARRAY OF CHAR);
+		VAR tm: LinLibc.tmDesc; sstr: ARRAY 64 OF SHORTCHAR; res: LinLibc.size_t;
+	BEGIN
+		tm.tm_hour := t.hour; tm.tm_min := t.minute; tm.tm_sec := t.second;
+		res := LinLibc.strftime(sstr, LEN(sstr), "%X", SYSTEM.VAL(LinLibc.tm, SYSTEM.ADR(tm)));
+		IF res > 0 THEN str := sstr$ELSE str := "invalid time"  END
+	END TimeToString;
+
+
+	PROCEDURE Init;
+		VAR 
+			datesHook: DatesHook;
+	BEGIN
+		NEW(datesHook); Dates.SetHook(datesHook);
+	END Init;
+
+BEGIN
+	Init
+END HostDates.

BIN
BlackBox/Linux/Lin/Mod/Dl.odc


+ 30 - 0
BlackBox/Linux/Lin/Mod/Dl.txt

@@ -0,0 +1,30 @@
+MODULE LinDl ["libdl.so.2"];
+
+	(* THIS IS TEXT COPY OF OpenBUGS Lin/Mod/Dl.odc *)
+	(* DO NOT EDIT *)
+
+	IMPORT SYSTEM;
+
+	CONST
+		(* dlOpen mode parameters *)
+		RTLD_LAZY* = 01H;	(* Lazy function call binding. *)
+		RTLD_NOW* = 02H;	(* Immediate function call binding. *)
+		RTLD_BINDING_MASK* = 03H;	(* Mask of binding time value. *)
+		RTLD_NOLOAD* = 04H;	(* Do not load the object. *)
+		RTLD_LOCAL* = 0;
+		RTLD_GLOBAL* = 100H;
+		RTDL_NODELETE* = 1000H;
+		
+		NULL* = 0;
+
+	TYPE
+		PtrVoid* = INTEGER;
+		HANDLE* = PtrVoid;
+		PtrSTR* = POINTER TO ARRAY [untagged] OF SHORTCHAR;
+
+	PROCEDURE [ccall] dlopen* (file: PtrSTR; mode: INTEGER): HANDLE; 
+	PROCEDURE [ccall] dlsym* (handle: HANDLE; name: PtrSTR): HANDLE; 
+	PROCEDURE [ccall] dlclose* (handle: HANDLE): INTEGER;
+	PROCEDURE [ccall] dlerror* (): PtrSTR;
+
+END LinDl.

BIN
BlackBox/Linux/Lin/Mod/Kernel.odc


+ 1991 - 0
BlackBox/Linux/Lin/Mod/Kernel.txt

@@ -0,0 +1,1991 @@
+MODULE Kernel;
+
+	(* THIS IS TEXT COPY OF Kernel.odc *)
+	(* DO NOT EDIT *)
+
+	(* A. V. Shiryaev, 2012.09
+		Linux Kernel
+		Based on 1.6-rc6 Windows Kernel
+		+ 20120822 Marc changes
+		Some parts taken from OpenBUGS linKernel
+
+		Most Windows-specific code removed
+		Some Windows-specific code commented and marked red
+		Windows COM-specific code re-marked from green to gray
+		Linux(/OpenBSD)-specific code marked green
+
+		TODO:
+			IsReadable
+			correct cmdLine
+	*)
+
+	IMPORT S := SYSTEM, Libc := LinLibc, Dl := LinDl;
+
+	CONST
+		strictStackSweep = TRUE;
+
+		nameLen* = 256;
+
+		littleEndian* = TRUE;
+		timeResolution* = 1000;	(* ticks per second *)
+
+		processor* = 10;	(* i386 *)
+
+		objType* = "ocf";	(* file types *)
+		symType* = "osf";
+		docType* = "odc";
+
+		(* loader constants *)
+		done* = 0;
+		fileNotFound* = 1;
+		syntaxError* = 2;
+		objNotFound* = 3;
+		illegalFPrint* = 4;
+		cyclicImport* = 5;
+		noMem* = 6;
+		commNotFound* = 7;
+		commSyntaxError* = 8;
+		moduleNotFound* = 9;
+
+		any = 1000000;
+
+		CX = 1;
+		SP = 4;	(* register number of stack pointer *)
+		FP = 5;	(* register number of frame pointer *)
+		ML = 3;	(* register which holds the module list at program start *)
+
+		N = 128 DIV 16;	(* free lists *)
+
+		(* kernel flags in module desc *)
+		init = 16; dyn = 17; dll = 24; iptrs = 30;
+
+		(* meta interface consts *)
+		mConst = 1; mTyp = 2; mVar = 3; mProc = 4; mField = 5;
+
+		debug = FALSE;
+
+
+		trapReturn = 1; (* Return value for sigsetjmp given from siglongjmp *)
+
+		(* constants for the message boxes *) 
+		mbClose* = -1; mbOk* = 0; mbCancel* =1; mbRetry* = 2; mbIgnore* = 3; mbYes* = 4; mbNo* = 5;
+
+	TYPE
+		Name* = ARRAY nameLen OF SHORTCHAR;
+		Command* = PROCEDURE;
+
+		Module* = POINTER TO RECORD [untagged]
+			next-: Module;
+			opts-: SET;	(* 0..15: compiler opts, 16..31: kernel flags *)
+			refcnt-: INTEGER;	(* <0: module invalidated *)
+			compTime-, loadTime-: ARRAY 6 OF SHORTINT;
+			ext-: INTEGER;	(* currently not used *)
+			term-: Command;	(* terminator *)
+			nofimps-, nofptrs-: INTEGER;
+			csize-, dsize-, rsize-: INTEGER;
+			code-, data-, refs-: INTEGER;
+			procBase-, varBase-: INTEGER;	(* meta base addresses *)
+			names-: POINTER TO ARRAY [untagged] OF SHORTCHAR;	(* names[0] = 0X *)
+			ptrs-: POINTER TO ARRAY [untagged] OF INTEGER;
+			imports-: POINTER TO ARRAY [untagged] OF Module;
+			export-: Directory;	(* exported objects (name sorted) *)
+			name-: Name
+		END;
+
+		Type* = POINTER TO RECORD [untagged]
+			(* record: ptr to method n at offset - 4 * (n+1) *)
+			size-: INTEGER;	(* record: size, array: #elem, dyn array: 0, proc: sigfp *)
+			mod-: Module;
+			id-: INTEGER;	(* name idx * 256 + lev * 16 + attr * 4 + form *)
+			base-: ARRAY 16 OF Type;	(* signature if form = ProcTyp *)
+			fields-: Directory;	(* new fields (declaration order) *)
+			ptroffs-: ARRAY any OF INTEGER	(* array of any length *)
+		END;
+
+		Object* = POINTER TO ObjDesc;
+
+		ObjDesc* = RECORD [untagged]
+			fprint-: INTEGER;
+			offs-: INTEGER;	(* pvfprint for record types *)
+			id-: INTEGER;	(* name idx * 256 + vis * 16 + mode *)
+			struct-: Type	(* id of basic type or pointer to typedesc/signature *)
+		END;
+
+		Directory* = POINTER TO RECORD [untagged]
+			num-: INTEGER;	(* number of entries *)
+			obj-: ARRAY any OF ObjDesc	(* array of any length *)
+		END;
+		
+		Signature* = POINTER TO RECORD [untagged]
+			retStruct-: Type;	(* id of basic type or pointer to typedesc or 0 *)
+			num-: INTEGER;	(* number of parameters *)
+			par-: ARRAY any OF RECORD [untagged]	(* parameters *)
+				id-: INTEGER;	(* name idx * 256 + kind *)
+				struct-: Type	(* id of basic type or pointer to typedesc *)
+			END
+		END;
+
+		Handler* = PROCEDURE;
+
+		Reducer* = POINTER TO ABSTRACT RECORD
+			next: Reducer
+		END;
+
+		Identifier* = ABSTRACT RECORD
+			typ*: INTEGER;
+			obj-: ANYPTR
+		END;
+
+		TrapCleaner* = POINTER TO ABSTRACT RECORD
+			next: TrapCleaner
+		END;
+
+		TryHandler* = PROCEDURE (a, b, c: INTEGER);
+
+
+		(* meta extension suport *)
+
+		ItemExt* = POINTER TO ABSTRACT RECORD END;
+
+		ItemAttr* = RECORD
+			obj*, vis*, typ*, adr*: INTEGER;
+			mod*: Module;
+			desc*: Type;
+			ptr*: S.PTR;
+			ext*: ItemExt
+		END;
+
+		Hook* = POINTER TO ABSTRACT RECORD END;
+
+		LoaderHook* = POINTER TO ABSTRACT RECORD (Hook) 
+			res*: INTEGER;
+			importing*, imported*, object*: ARRAY 256 OF CHAR
+		END;
+
+		GuiHook* = POINTER TO ABSTRACT RECORD (Hook) END; (* Implemented by HostGnome *)
+
+		Block = POINTER TO RECORD [untagged]
+			tag: Type;
+			last: INTEGER;		(* arrays: last element *)
+			actual: INTEGER;	(* arrays: used during mark phase *)
+			first: INTEGER		(* arrays: first element *)
+		END;
+
+		FreeBlock = POINTER TO FreeDesc;
+
+		FreeDesc = RECORD [untagged]
+			tag: Type;		(* f.tag = ADR(f.size) *)
+			size: INTEGER;
+			next: FreeBlock
+		END;
+
+		Cluster = POINTER TO RECORD [untagged]
+			size: INTEGER;	(* total size *)
+			next: Cluster;
+			max: INTEGER
+			(* start of first block *)
+		END;
+
+		FList = POINTER TO RECORD
+			next: FList;
+			blk: Block;
+			iptr, aiptr: BOOLEAN
+		END;
+
+		CList = POINTER TO RECORD
+			next: CList;
+			do: Command;
+			trapped: BOOLEAN
+		END;
+
+
+		PtrType = RECORD v: S.PTR END;	(* used for array of pointer *)
+		Char8Type = RECORD v: SHORTCHAR END;
+		Char16Type = RECORD v: CHAR END;
+		Int8Type = RECORD v: BYTE END;
+		Int16Type = RECORD v: SHORTINT END;
+		Int32Type = RECORD v: INTEGER END;
+		Int64Type = RECORD v: LONGINT END;
+		BoolType = RECORD v: BOOLEAN END;
+		SetType = RECORD v: SET END;
+		Real32Type = RECORD v: SHORTREAL END;
+		Real64Type = RECORD v: REAL END;
+		ProcType = RECORD v: PROCEDURE END;
+		UPtrType = RECORD v: INTEGER END;
+		StrPtr = POINTER TO ARRAY [untagged] OF SHORTCHAR;
+
+		(* Linux specific boot loader info. Record must be identical to struct in the loader. *)
+		BootInfo* = POINTER TO RECORD [untagged]
+			modList: Module;
+			argc-: INTEGER;
+			argv-: Libc.StrArray
+		END;
+
+	VAR
+		baseStack: INTEGER;	(* modList, root, and baseStack must be together for remote debugging *)
+		root: Cluster;	(* cluster list *)
+		modList-: Module;	(* root of module list *)
+		trapCount-: INTEGER;
+		err-, pc-, sp-, fp-, stack-, val-: INTEGER;
+
+		free: ARRAY N OF FreeBlock;	(* free list *)
+		sentinelBlock: FreeDesc;
+		sentinel: FreeBlock;
+		candidates: ARRAY 1024 OF INTEGER;
+		nofcand: INTEGER;
+		allocated: INTEGER;	(* bytes allocated on BlackBox heap *)
+		total: INTEGER;	(* current total size of BlackBox heap *)
+		used: INTEGER;	(* bytes allocated on system heap *)
+		finalizers: FList;
+		hotFinalizers: FList;
+		cleaners: CList;
+		reducers: Reducer;
+		trapStack: TrapCleaner;
+		actual: Module;	(* valid during module initialization *)
+
+		res: INTEGER;	(* auxiliary global variables used for trap handling *)
+		old: INTEGER;
+
+		trapViewer, trapChecker: Handler;
+		trapped, guarded, secondTrap: BOOLEAN;
+		interrupted: BOOLEAN;
+		static, inDll, terminating: BOOLEAN;
+		restart: Command;
+
+		told, shift: INTEGER;	(* used in Time() *)
+
+		loader: LoaderHook;
+		loadres: INTEGER;
+
+		wouldFinalize: BOOLEAN;
+
+		watcher*: PROCEDURE (event: INTEGER);	(* for debugging *)
+
+		zerofd: INTEGER;
+
+		loopContext: Libc.sigjmp_buf; (* trap return context, if no Kernel.Try has been used. *)
+		currentTryContext: POINTER TO Libc.sigjmp_buf; (* trap return context, if Kernel.Try has been used. *)
+		
+		guiHook: GuiHook;
+		
+		cmdLine-: ARRAY 1024 OF CHAR;
+
+		(* !!! This variable has to be the last variable in the list.  !!! *)
+		bootInfo-: BootInfo;
+
+	(* code procedures for fpu *)
+
+	PROCEDURE [1] FINIT 0DBH, 0E3H;
+	PROCEDURE [1] FLDCW 0D9H, 06DH, 0FCH;	(* -4, FP *)
+	PROCEDURE [1] FSTCW 0D9H, 07DH, 0FCH;	(* -4, FP *)
+
+	(* code procedure for memory erase *)
+
+	PROCEDURE [code] Erase (adr, words: INTEGER)	
+		089H, 0C7H,	(* MOV EDI, EAX *)
+		031H, 0C0H,	(* XOR EAX, EAX *)
+		059H,			(* POP ECX *)
+		0F2H, 0ABH;	(* REP STOS *)
+
+	(* code procedure for stack allocate *)
+
+	PROCEDURE [code] ALLOC (* argument in CX *)
+	(*
+		PUSH	EAX
+		ADD	ECX,-5
+		JNS	L0
+		XOR	ECX,ECX
+	L0: AND	ECX,-4	(n-8+3)/4*4
+		MOV	EAX,ECX
+		AND	EAX,4095
+		SUB	ESP,EAX
+		MOV	EAX,ECX
+		SHR	EAX,12
+		JEQ	L2
+	L1: PUSH	0
+		SUB	ESP,4092
+		DEC	EAX
+		JNE	L1
+	L2: ADD	ECX,8
+		MOV	EAX,[ESP,ECX,-4]
+		PUSH	EAX
+		MOV	EAX,[ESP,ECX,-4]
+		SHR	ECX,2
+		RET
+	*);
+
+	PROCEDURE (VAR id: Identifier) Identified* (): BOOLEAN,	NEW, ABSTRACT;
+	PROCEDURE (r: Reducer) Reduce* (full: BOOLEAN),	NEW, ABSTRACT;
+	PROCEDURE (c: TrapCleaner) Cleanup*,	NEW, EMPTY;
+
+
+	(* meta extension suport *)
+
+	PROCEDURE (e: ItemExt) Lookup* (name: ARRAY OF CHAR; VAR i: ANYREC), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) Index* (index: INTEGER; VAR elem: ANYREC), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) Deref* (VAR ref: ANYREC), NEW, ABSTRACT;
+
+	PROCEDURE (e: ItemExt) Valid* (): BOOLEAN, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) Size* (): INTEGER, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) BaseTyp* (): INTEGER, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) Len* (): INTEGER, NEW, ABSTRACT;
+
+	PROCEDURE (e: ItemExt) Call* (OUT ok: BOOLEAN), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) BoolVal* (): BOOLEAN, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutBoolVal* (x: BOOLEAN), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) CharVal* (): CHAR, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutCharVal* (x: CHAR), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) IntVal* (): INTEGER, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutIntVal* (x: INTEGER), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) LongVal* (): LONGINT, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutLongVal* (x: LONGINT), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) RealVal* (): REAL, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutRealVal* (x: REAL), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) SetVal* (): SET, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutSetVal* (x: SET), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PtrVal* (): ANYPTR, NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutPtrVal* (x: ANYPTR), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) GetSStringVal* (OUT x: ARRAY OF SHORTCHAR;
+																	OUT ok: BOOLEAN), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutSStringVal* (IN x: ARRAY OF SHORTCHAR;
+																	OUT ok: BOOLEAN), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) GetStringVal* (OUT x: ARRAY OF CHAR; OUT ok: BOOLEAN), NEW, ABSTRACT;
+	PROCEDURE (e: ItemExt) PutStringVal* (IN x: ARRAY OF CHAR; OUT ok: BOOLEAN), NEW, ABSTRACT;
+
+
+	(* -------------------- miscellaneous tools -------------------- *)
+
+	PROCEDURE Msg (IN str: ARRAY OF CHAR);
+		VAR ss: ARRAY 1024 OF SHORTCHAR; res, l: INTEGER;
+	BEGIN
+		ss := SHORT(str);
+		l := LEN(ss$);
+		ss[l] := 0AX; ss[l + 1] := 0X;
+		res := Libc.printf(ss)
+	END Msg;
+
+	PROCEDURE Int (x: LONGINT);
+		VAR j, k: INTEGER; ch: CHAR; a, s: ARRAY 32 OF CHAR;
+	BEGIN
+		IF x # MIN(LONGINT) THEN
+			IF x < 0 THEN s[0] := "-"; k := 1; x := -x ELSE k := 0 END;
+			j := 0; REPEAT a[j] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(j) UNTIL x = 0
+		ELSE
+			a := "8085774586302733229"; s[0] := "-"; k := 1;
+			j := 0; WHILE a[j] # 0X DO INC(j) END
+		END;
+		ASSERT(k + j < LEN(s), 20);
+		REPEAT DEC(j); ch := a[j]; s[k] := ch; INC(k) UNTIL j = 0;
+		s[k] := 0X;
+		Msg(s);
+	END Int;
+	
+	PROCEDURE (h: GuiHook)  MessageBox* (
+		title, msg: ARRAY OF CHAR; buttons: SET): INTEGER, NEW, ABSTRACT;
+	PROCEDURE (h: GuiHook)  Beep*, NEW, ABSTRACT;
+
+	(* Is extended by HostGnome to show dialogs. If no dialog is present or
+	    if the dialog is not closed by using one button, then "mbClose" is returned *)
+	PROCEDURE MessageBox* (title, msg: ARRAY OF CHAR; buttons: SET): INTEGER;
+		VAR res: INTEGER;
+	BEGIN
+		IF guiHook # NIL THEN
+			res := guiHook.MessageBox(title, msg, buttons)
+		ELSE
+			Msg(" ");
+			Msg("****");
+			Msg("* " + title);
+			Msg("* " + msg);
+			Msg("****");
+			res := mbClose;
+		END;
+		RETURN res
+	END MessageBox;
+
+	PROCEDURE SetGuiHook* (hook: GuiHook);
+	BEGIN
+		guiHook := hook
+	END SetGuiHook;
+
+	PROCEDURE SplitName* (name: ARRAY OF CHAR; VAR head, tail: ARRAY OF CHAR);
+		(* portable *)
+		VAR i, j: INTEGER; ch, lch: CHAR;
+	BEGIN
+		i := 0; ch := name[0];
+		IF ch # 0X THEN
+			REPEAT
+				head[i] := ch; lch := ch; INC(i); ch := name[i]
+			UNTIL (ch = 0X)
+				OR ((ch >= "A") & (ch <= "Z") OR (ch >= "À") & (ch # "×") & (ch <= "Þ"))
+					& ((lch < "A") OR (lch > "Z") & (lch < "À") OR (lch = "×") OR (lch > "Þ"));
+			head[i] := 0X; j := 0;
+			WHILE ch # 0X DO tail[j] := ch; INC(i); INC(j); ch := name[i] END;
+			tail[j] := 0X;
+			IF tail = "" THEN tail := head$; head := "" END
+		ELSE head := ""; tail := ""
+		END
+	END SplitName;
+
+	PROCEDURE MakeFileName* (VAR name: ARRAY OF CHAR; type: ARRAY OF CHAR);
+		VAR i, j: INTEGER; ext: ARRAY 8 OF CHAR; ch: CHAR;
+	BEGIN
+		i := 0;
+		WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END;
+		IF name[i] = "." THEN
+			IF name[i + 1] = 0X THEN name[i] := 0X END
+		ELSIF i < LEN(name) - 4 THEN
+			IF type = "" THEN ext := docType ELSE ext := type$ END;
+			name[i] := "."; INC(i); j := 0; ch := ext[0];
+			WHILE ch # 0X DO
+				IF (ch >= "A") & (ch <= "Z") THEN
+					ch := CHR(ORD(ch) + ORD("a") - ORD("A"))
+				END;
+				name[i] := ch; INC(i); INC(j); ch := ext[j]
+			END;
+			name[i] := 0X
+		END
+	END MakeFileName;
+
+	PROCEDURE Time* (): LONGINT;
+		VAR t: INTEGER;
+	BEGIN
+		(* t := WinApi.GetTickCount(); *)
+
+		(* Linux *)
+		t := Libc.clock() DIV (Libc.CLOCKS_PER_SECOND DIV 1000); (* processor time to milliseconds *)
+
+		IF t < told THEN INC(shift) END;
+		told := t;
+		RETURN shift * 100000000L + t
+	END Time;
+
+	PROCEDURE Beep* ();
+		VAR ss: ARRAY 2 OF SHORTCHAR;
+	BEGIN
+		IF guiHook # NIL THEN
+			guiHook.Beep
+		ELSE
+			ss[0] := 007X; ss[1] := 0X;
+			res := Libc.printf(ss); res := Libc.fflush(Libc.NULL)
+		END
+	END Beep;
+
+	PROCEDURE SearchProcVar* (var: INTEGER; VAR m: Module; VAR adr: INTEGER);
+	BEGIN
+		adr := var; m := NIL;
+		IF var # 0 THEN
+			m := modList;
+			WHILE (m # NIL) & ((var < m.code) OR (var >= m.code + m.csize)) DO m := m.next END;
+			IF m # NIL THEN DEC(adr, m.code) END
+		END
+	END SearchProcVar;
+
+
+	(* -------------------- system memory management --------------------- *)
+
+	(* A. V. Shiryaev, 2012.09: NOTE: it seems that GC works correctly with positive addesses only *)
+
+	PROCEDURE BZero4 (adr: Libc.PtrVoid; len: INTEGER);
+	BEGIN
+		ASSERT(adr MOD 4 = 0, 20);
+		ASSERT(len MOD 4 = 0, 21);
+		len := len DIV 4;
+		WHILE len > 0 DO
+			S.PUT(adr, 0);
+			INC(adr, 4);
+			DEC(len)
+		END
+	END BZero4;
+
+(*
+	PROCEDURE HeapAlloc (adr: INTEGER; size: INTEGER; prot: SET): Libc.PtrVoid;
+		VAR
+			x: Libc.PtrVoid;
+			res: INTEGER;
+	BEGIN
+		x := Libc.calloc(1, size); (* calloc initialize allocated space to zero *)
+		IF x # Libc.NULL THEN
+			res := Libc.mprotect(x, size, prot);
+			IF res # 0 THEN
+				Libc.free(x);
+				x := Libc.NULL;
+				Msg("Kernel.HeapAlloc: mprotect failed!");
+				HALT(100)
+			END
+		END;
+		RETURN x
+	END HeapAlloc;
+*)
+	PROCEDURE HeapAlloc (adr: Libc.PtrVoid; size: INTEGER; prot: SET): Libc.PtrVoid;
+		VAR x: Libc.PtrVoid;
+	BEGIN
+		x := Libc.mmap(adr, size, prot, Libc.MAP_PRIVATE + Libc.MAP_ANON, zerofd, 0);
+		IF x = Libc.MAP_FAILED THEN
+			x := Libc.NULL
+		ELSE
+			BZero4(x, size)
+		END;
+		RETURN x
+	END HeapAlloc;
+
+(*
+	PROCEDURE HeapFree (adr: Libc.PtrVoid; size: INTEGER);
+		VAR res: INTEGER;
+	BEGIN
+(*
+		BZero4(adr, size);
+		res := Libc.mprotect(adr, size, Libc.PROT_NONE);
+		ASSERT(res = 0, 100);
+*)
+		Libc.free(adr)
+	END HeapFree;
+*)
+	PROCEDURE HeapFree (adr: Libc.PtrVoid; size: INTEGER);
+		VAR res: INTEGER;
+	BEGIN
+(*
+		BZero4(adr, size);
+		res := Libc.mprotect(adr, size, Libc.PROT_NONE);
+		ASSERT(res = 0, 100);
+*)
+		res := Libc.munmap(adr, size);
+		ASSERT(res = 0, 101)
+	END HeapFree;
+
+	PROCEDURE AllocHeapMem (size: INTEGER; VAR c: Cluster);
+		(* allocate at least size bytes, typically at least 256 kbytes are allocated *)
+		CONST N = 65536;	(* cluster size for dll *)
+			prot = Libc.PROT_READ + Libc.PROT_WRITE (* + Libc.PROT_EXEC *);
+		VAR adr: INTEGER;
+			allocated: INTEGER;
+	BEGIN
+		INC(size, 16);
+		ASSERT(size > 0, 100); adr := 0;
+		IF size < N THEN adr := HeapAlloc(1, N, prot) END;
+		IF adr = 0 THEN adr := HeapAlloc(1, size, prot); allocated := size ELSE allocated := N END;
+		IF adr = 0 THEN c := NIL
+		ELSE
+			c := S.VAL(Cluster, (adr + 15) DIV 16 * 16); c.max := adr;
+			c.size := allocated - (S.VAL(INTEGER, c) - adr);
+			INC(used, c.size); INC(total, c.size)
+		END
+		(* post: (c = NIL) OR (c MOD 16 = 0) & (c.size >= size) *)
+	END AllocHeapMem;
+
+	PROCEDURE FreeHeapMem (c: Cluster);
+	BEGIN
+		DEC(used, c.size); DEC(total, c.size);
+		HeapFree(c.max, (S.VAL(INTEGER, c) - c.max) + c.size)
+	END FreeHeapMem;
+
+	PROCEDURE AllocModMem* (descSize, modSize: INTEGER; VAR descAdr, modAdr: INTEGER);
+		CONST
+			prot = Libc.PROT_READ + Libc.PROT_WRITE (* + Libc.PROT_EXEC *);
+	BEGIN
+		descAdr := HeapAlloc(0, descSize, prot);
+		IF descAdr # 0 THEN
+			modAdr := HeapAlloc(0, modSize, prot);
+			IF modAdr # 0 THEN INC(used, descSize + modSize)
+			ELSE HeapFree(descAdr, descSize); descAdr := 0
+			END
+		ELSE modAdr := 0
+		END
+	END AllocModMem;
+
+	PROCEDURE DeallocModMem* (descSize, modSize, descAdr, modAdr: INTEGER);
+	BEGIN
+		DEC(used, descSize + modSize);
+		HeapFree(descAdr, descSize);
+		HeapFree(modAdr, modSize)
+	END DeallocModMem;
+
+	PROCEDURE InvalModMem (modSize, modAdr: INTEGER);
+	BEGIN
+		DEC(used, modSize);
+		HeapFree(modAdr, modSize)
+	END InvalModMem;
+
+(*
+	PROCEDURE IsReadable* (from, to: INTEGER): BOOLEAN;
+		(* check wether memory between from (incl.) and to (excl.) may be read *)
+	BEGIN
+		RETURN WinApi.IsBadReadPtr(from, to - from) = 0
+	END IsReadable;
+*)
+
+	(* NOTE:
+		TRUE result DOES NOT GUARANTEE what mem region is REALLY accessible! (implementation limit) *)
+	PROCEDURE IsReadable* (from, to: INTEGER): BOOLEAN;
+		(* check wether memory between from (incl.) and to (excl.) may be read *)
+		VAR nullfd: INTEGER;
+			res1, errno: INTEGER;
+			res: BOOLEAN;
+	BEGIN
+		ASSERT(from < to, 20);
+
+		res := FALSE;
+
+		nullfd := Libc.open("/dev/null", Libc.O_WRONLY, {});
+		IF nullfd >= 0 THEN
+			res1 := Libc.write(nullfd, from, to - from);
+			IF res1 = -1 THEN
+				S.GET(Libc.__errno_location(), errno);
+				IF errno = Libc.EFAULT THEN
+					res := FALSE
+				ELSE
+					HALT(101)
+				END
+			ELSE ASSERT(res1 = to - from);
+				res := TRUE
+			END;
+			res1 := Libc.close(nullfd)
+		ELSE ASSERT(nullfd = -1);
+			HALT(100)
+		END;
+
+		RETURN res
+	END IsReadable;
+
+	(* --------------------- NEW implementation (portable) -------------------- *)
+
+	PROCEDURE^ NewBlock (size: INTEGER): Block;
+
+	PROCEDURE NewRec* (typ: INTEGER): INTEGER;	(* implementation of NEW(ptr) *)
+		VAR size: INTEGER; b: Block; tag: Type; l: FList;
+	BEGIN
+		IF ODD(typ) THEN	(* record contains interface pointers *)
+			tag := S.VAL(Type, typ - 1);
+			b := NewBlock(tag.size);
+			IF b = NIL THEN RETURN 0 END;
+			b.tag := tag;
+			l := S.VAL(FList, S.ADR(b.last));	(* anchor new object! *)
+			l := S.VAL(FList, NewRec(S.TYP(FList)));	(* NEW(l) *)
+			l.blk := b; l.iptr := TRUE; l.next := finalizers; finalizers := l;
+			RETURN S.ADR(b.last)
+		ELSE
+			tag := S.VAL(Type, typ);
+			b := NewBlock(tag.size);
+			IF b = NIL THEN RETURN 0 END;
+			b.tag := tag; S.GET(typ - 4, size);
+			IF size # 0 THEN	(* record uses a finalizer *)
+				l := S.VAL(FList, S.ADR(b.last));	(* anchor new object! *)
+				l := S.VAL(FList, NewRec(S.TYP(FList)));	(* NEW(l) *)
+				l.blk := b; l.next := finalizers; finalizers := l
+			END;
+			RETURN S.ADR(b.last)
+		END
+	END NewRec;
+
+	PROCEDURE NewArr* (eltyp, nofelem, nofdim: INTEGER): INTEGER;	(* impl. of NEW(ptr, dim0, dim1, ...) *)
+		VAR b: Block; size, headSize: INTEGER; t: Type; fin: BOOLEAN; l: FList;
+	BEGIN
+		IF (nofdim < 0)OR(nofdim>1FFFFFFCH) THEN RETURN 0 END;(*20120822 Marc*)
+		headSize := 4 * nofdim + 12; fin := FALSE;
+		CASE eltyp OF
+(*
+		| -1: eltyp := S.ADR(IntPtrType); fin := TRUE
+*)
+		| -1: HALT(100)
+		| 0: eltyp := S.ADR(PtrType)
+		| 1: eltyp := S.ADR(Char8Type)
+		| 2: eltyp := S.ADR(Int16Type)
+		| 3: eltyp := S.ADR(Int8Type)
+		| 4: eltyp := S.ADR(Int32Type)
+		| 5: eltyp := S.ADR(BoolType)
+		| 6: eltyp := S.ADR(SetType)
+		| 7: eltyp := S.ADR(Real32Type)
+		| 8: eltyp := S.ADR(Real64Type)
+		| 9: eltyp := S.ADR(Char16Type)
+		| 10: eltyp := S.ADR(Int64Type)
+		| 11: eltyp := S.ADR(ProcType)
+		| 12: eltyp := S.ADR(UPtrType)
+		ELSE	(* eltyp is desc *)
+			IF ODD(eltyp) THEN DEC(eltyp); fin := TRUE END
+		END;
+		t := S.VAL(Type, eltyp);
+		ASSERT(t .size> 0,100);
+		IF (nofelem < 0) OR( (7FFFFFFFH-headSize) DIV t.size < nofelem) THEN (* 20120822 Marc*)
+			RETURN 0 
+		END; 
+		size := headSize + nofelem * t.size;
+		b := NewBlock(size);
+		IF b = NIL THEN RETURN 0 END;
+		b.tag := S.VAL(Type, eltyp + 2);	(* tag + array mark *)
+		b.last := S.ADR(b.last) + size - t.size;	(* pointer to last elem *)
+		b.first := S.ADR(b.last) + headSize;	(* pointer to first elem *)
+		IF fin THEN
+			l := S.VAL(FList, S.ADR(b.last));	(* anchor new object! *)
+			l := S.VAL(FList, NewRec(S.TYP(FList)));	(* NEW(l) *)
+			l.blk := b; l.aiptr := TRUE; l.next := finalizers; finalizers := l
+		END;
+		RETURN S.ADR(b.last)
+	END NewArr;
+
+
+	(* -------------------- handler installation (portable) --------------------- *)
+
+	PROCEDURE ThisFinObj* (VAR id: Identifier): ANYPTR;
+		VAR l: FList;
+	BEGIN
+		ASSERT(id.typ # 0, 100);
+		l := finalizers;
+		WHILE l # NIL DO
+			IF S.VAL(INTEGER, l.blk.tag) = id.typ THEN
+				id.obj := S.VAL(ANYPTR, S.ADR(l.blk.last));
+				IF id.Identified() THEN RETURN id.obj END
+			END;
+			l := l.next
+		END;
+		RETURN NIL
+	END ThisFinObj;
+
+	PROCEDURE InstallReducer* (r: Reducer);
+	BEGIN
+		r.next := reducers; reducers := r
+	END InstallReducer;
+
+	PROCEDURE InstallTrapViewer* (h: Handler);
+	BEGIN
+		trapViewer := h
+	END InstallTrapViewer;
+
+	PROCEDURE InstallTrapChecker* (h: Handler);
+	BEGIN
+		trapChecker := h
+	END InstallTrapChecker;
+
+	PROCEDURE PushTrapCleaner* (c: TrapCleaner);
+		VAR t: TrapCleaner;
+	BEGIN
+		t := trapStack; WHILE (t # NIL) & (t # c) DO t := t.next END;
+		ASSERT(t = NIL, 20);
+		c.next := trapStack; trapStack := c
+	END PushTrapCleaner;
+
+	PROCEDURE PopTrapCleaner* (c: TrapCleaner);
+		VAR t: TrapCleaner;
+	BEGIN
+		t := NIL;
+		WHILE (trapStack # NIL) & (t # c) DO
+			t := trapStack; trapStack := trapStack.next
+		END
+	END PopTrapCleaner;
+
+	PROCEDURE InstallCleaner* (p: Command);
+		VAR c: CList;
+	BEGIN
+		c := S.VAL(CList, NewRec(S.TYP(CList)));	(* NEW(c) *)
+		c.do := p; c.trapped := FALSE; c.next := cleaners; cleaners := c
+	END InstallCleaner;
+
+	PROCEDURE RemoveCleaner* (p: Command);
+		VAR c0, c: CList;
+	BEGIN
+		c := cleaners; c0 := NIL;
+		WHILE (c # NIL) & (c.do # p) DO c0 := c; c := c.next END;
+		IF c # NIL THEN
+			IF c0 = NIL THEN cleaners := cleaners.next ELSE c0.next := c.next END
+		END
+	END RemoveCleaner;
+
+	PROCEDURE Cleanup*;
+		VAR c, c0: CList;
+	BEGIN
+		c := cleaners; c0 := NIL;
+		WHILE c # NIL DO
+			IF ~c.trapped THEN
+				c.trapped := TRUE; c.do; c.trapped := FALSE; c0 := c
+			ELSE
+				IF c0 = NIL THEN cleaners := cleaners.next
+				ELSE c0.next := c.next
+				END
+			END;
+			c := c.next
+		END
+	END Cleanup;
+
+	(* -------------------- meta information (portable) --------------------- *)
+
+	PROCEDURE (h: LoaderHook) ThisMod* (IN name: ARRAY OF SHORTCHAR): Module, NEW, ABSTRACT;
+
+	PROCEDURE SetLoaderHook*(h: LoaderHook);
+	BEGIN
+		loader := h
+	END SetLoaderHook;
+
+	PROCEDURE InitModule (mod: Module);	(* initialize linked modules *)
+		VAR body: Command;
+			res: INTEGER; errno: INTEGER;
+	BEGIN
+		IF ~(dyn IN mod.opts) & (mod.next # NIL) & ~(init IN mod.next.opts) THEN InitModule(mod.next) END;
+		IF ~(init IN mod.opts) THEN
+			body := S.VAL(Command, mod.code);
+			INCL(mod.opts, init);
+			actual := mod;
+
+			(* A. V. Shiryaev: Allow execution on code pages *)
+				res := Libc.mprotect(mod.code, mod.csize,
+					Libc.PROT_READ + Libc.PROT_WRITE + Libc.PROT_EXEC);
+				IF res = -1 THEN
+					S.GET( Libc.__errno_location(), errno );
+					Msg("ERROR: Kernel.InitModule: mprotect failed!");
+					Msg(mod.name$); Int(mod.code); Int(mod.csize); Int(errno);
+					HALT(100)
+				ELSE ASSERT(res = 0)
+				END;
+
+			body(); actual := NIL
+		END
+	END InitModule;
+
+	PROCEDURE ThisLoadedMod* (IN name: ARRAY OF SHORTCHAR): Module;	(* loaded modules only *)
+		VAR m: Module;
+	BEGIN
+		loadres := done;
+		m := modList;
+		WHILE (m # NIL) & ((m.name # name) OR (m.refcnt < 0)) DO m := m.next END;
+		IF (m # NIL) & ~(init IN m.opts) THEN InitModule(m) END;
+		IF m = NIL THEN loadres := moduleNotFound END;
+		RETURN m
+	END ThisLoadedMod;
+
+	PROCEDURE ThisMod* (IN name: ARRAY OF CHAR): Module;
+		VAR n : Name;
+	BEGIN
+		n := SHORT(name$);
+		IF loader # NIL THEN
+			loader.res := done;
+			RETURN loader.ThisMod(n)
+		ELSE
+			RETURN ThisLoadedMod(n)
+		END
+	END ThisMod;
+
+	PROCEDURE LoadMod* (IN name: ARRAY OF CHAR);
+		VAR m: Module;
+	BEGIN
+		m := ThisMod(name)
+	END LoadMod;
+
+	PROCEDURE GetLoaderResult* (OUT res: INTEGER; OUT importing, imported, object: ARRAY OF CHAR);
+	BEGIN
+		IF loader # NIL THEN
+			res := loader.res;
+			importing := loader.importing$;
+			imported := loader.imported$;
+			object := loader.object$
+		ELSE
+			res := loadres;
+			importing := "";
+			imported := "";
+			object := ""
+		END
+	END GetLoaderResult;
+
+	PROCEDURE ThisObject* (mod: Module; name: ARRAY OF SHORTCHAR): Object;
+		VAR l, r, m: INTEGER; p: StrPtr;
+	BEGIN
+		l := 0; r := mod.export.num;
+		WHILE l < r DO	(* binary search *)
+			m := (l + r) DIV 2;
+			p := S.VAL(StrPtr, S.ADR(mod.names[mod.export.obj[m].id DIV 256]));
+			IF p^ = name THEN RETURN S.VAL(Object, S.ADR(mod.export.obj[m])) END;
+			IF p^ < name THEN l := m + 1 ELSE r := m END
+		END;
+		RETURN NIL
+	END ThisObject;
+
+	PROCEDURE ThisDesc* (mod: Module; fprint: INTEGER): Object;
+		VAR i, n: INTEGER;
+	BEGIN
+		i := 0; n := mod.export.num;
+		WHILE (i < n) & (mod.export.obj[i].id DIV 256 = 0) DO 
+			IF mod.export.obj[i].offs = fprint THEN RETURN S.VAL(Object, S.ADR(mod.export.obj[i])) END;
+			INC(i)
+		END;
+		RETURN NIL
+	END ThisDesc;
+
+	PROCEDURE ThisField* (rec: Type; name: ARRAY OF SHORTCHAR): Object;
+		VAR n: INTEGER; p: StrPtr; obj: Object; m: Module;
+	BEGIN
+		m := rec.mod;
+		obj := S.VAL(Object, S.ADR(rec.fields.obj[0])); n := rec.fields.num;
+		WHILE n > 0 DO
+			p := S.VAL(StrPtr, S.ADR(m.names[obj.id DIV 256]));
+			IF p^ = name THEN RETURN obj END;
+			DEC(n); INC(S.VAL(INTEGER, obj), 16)
+		END;
+		RETURN NIL
+	END ThisField;
+
+	PROCEDURE ThisCommand* (mod: Module; name: ARRAY OF SHORTCHAR): Command;
+		VAR x: Object; sig: Signature;
+	BEGIN
+		x := ThisObject(mod, name);
+		IF (x # NIL) & (x.id MOD 16 = mProc) THEN
+			sig := S.VAL(Signature, x.struct);
+			IF (sig.retStruct = NIL) & (sig.num = 0) THEN RETURN S.VAL(Command, mod.procBase + x.offs) END
+		END;
+		RETURN NIL
+	END ThisCommand;
+
+	PROCEDURE ThisType* (mod: Module; name: ARRAY OF SHORTCHAR): Type;
+		VAR x: Object;
+	BEGIN
+		x := ThisObject(mod, name);
+		IF (x # NIL) & (x.id MOD 16 = mTyp) & (S.VAL(INTEGER, x.struct) DIV 256 # 0) THEN
+			RETURN x.struct
+		ELSE
+			RETURN NIL
+		END
+	END ThisType;
+
+	PROCEDURE TypeOf* (IN rec: ANYREC): Type;
+	BEGIN
+		RETURN S.VAL(Type, S.TYP(rec))
+	END TypeOf;
+
+	PROCEDURE LevelOf* (t: Type): SHORTINT;
+	BEGIN
+		RETURN SHORT(t.id DIV 16 MOD 16)
+	END LevelOf;
+
+	PROCEDURE NewObj* (VAR o: S.PTR; t: Type);
+		VAR i: INTEGER;
+	BEGIN
+		IF t.size = -1 THEN o := NIL
+		ELSE
+			i := 0; WHILE t.ptroffs[i] >= 0 DO INC(i) END;
+			IF t.ptroffs[i+1] >= 0 THEN INC(S.VAL(INTEGER, t)) END;	(* with interface pointers *)
+			o := S.VAL(S.PTR, NewRec(S.VAL(INTEGER, t)))	(* generic NEW *)
+		END
+	END NewObj;
+
+	PROCEDURE GetObjName* (mod: Module; obj: Object; VAR name: Name);
+		VAR p: StrPtr;
+	BEGIN
+		p := S.VAL(StrPtr, S.ADR(mod.names[obj.id DIV 256]));
+		name := p^$
+	END GetObjName;
+
+	PROCEDURE GetTypeName* (t: Type; VAR name: Name);
+		VAR p: StrPtr;
+	BEGIN
+		p := S.VAL(StrPtr, S.ADR(t.mod.names[t.id DIV 256]));
+		name := p^$
+	END GetTypeName;
+
+	PROCEDURE RegisterMod* (mod: Module);
+		VAR i: INTEGER;
+			t: Libc.time_t; tm: Libc.tm;
+	BEGIN
+		mod.next := modList; modList := mod; mod.refcnt := 0; INCL(mod.opts, dyn); i := 0;
+		WHILE i < mod.nofimps DO
+			IF mod.imports[i] # NIL THEN INC(mod.imports[i].refcnt) END;
+			INC(i)
+		END;
+
+		t := Libc.time(NIL);
+		tm := Libc.localtime(t);
+		mod.loadTime[0] := SHORT(tm.tm_year + 1900); (* Linux counts years from 1900 but BlackBox from 0000 *)
+		mod.loadTime[1] := SHORT(tm.tm_mon + 1) (* Linux month range 0-11 but BB month range 1-12 *);
+		mod.loadTime[2] := SHORT(tm.tm_mday);
+		mod.loadTime[3] := SHORT(tm.tm_hour);
+		mod.loadTime[4] := SHORT(tm.tm_min);
+		mod.loadTime[5] := SHORT(tm.tm_sec); 
+		tm := NIL;
+
+		IF ~(init IN mod.opts) THEN InitModule(mod) END
+	END RegisterMod;
+
+	PROCEDURE^ Collect*;
+
+	PROCEDURE UnloadMod* (mod: Module);
+		VAR i: INTEGER; t: Command;
+	BEGIN
+		IF mod.refcnt = 0 THEN
+			t := mod.term; mod.term := NIL;
+			IF t # NIL THEN t() END;	(* terminate module *)
+			i := 0;
+			WHILE i < mod.nofptrs DO	(* release global pointers *)
+				S.PUT(mod.varBase + mod.ptrs[i], 0); INC(i)
+			END;
+(*
+			ReleaseIPtrs(mod);	(* release global interface pointers *)
+*)
+			Collect;	(* call finalizers *)
+			i := 0;
+			WHILE i < mod.nofimps DO	(* release imported modules *)
+				IF mod.imports[i] # NIL THEN DEC(mod.imports[i].refcnt) END;
+				INC(i)
+			END;
+			mod.refcnt := -1;
+			IF dyn IN mod.opts THEN	(* release memory *)
+				InvalModMem(mod.data + mod.dsize - mod.refs, mod.refs)
+			END
+		END
+	END UnloadMod;
+
+	(* -------------------- dynamic procedure call  --------------------- *)	(* COMPILER DEPENDENT *)
+
+	PROCEDURE [1] PUSH (p: INTEGER) 050H;	(* push AX *)
+	PROCEDURE [1] CALL (a: INTEGER) 0FFH, 0D0H;	(* call AX *)
+	PROCEDURE [1] RETI (): LONGINT;
+	PROCEDURE [1] RETR (): REAL;
+	
+	(*
+		type				par
+		32 bit scalar	value
+		64 bit scalar	low hi
+		var scalar		address
+		record			address tag
+		array			  address size
+		open array	   address length .. length
+	*)
+	
+	PROCEDURE Call* (adr: INTEGER; sig: Signature; IN par: ARRAY OF INTEGER; n: INTEGER): LONGINT;
+		VAR p, kind, sp, size: INTEGER; typ: Type; r: REAL;
+	BEGIN
+		p := sig.num;
+		WHILE p > 0 DO	(* push parameters from right to left *)
+			DEC(p);
+			typ := sig.par[p].struct;
+			kind := sig.par[p].id MOD 16;
+			IF (S.VAL(INTEGER, typ) DIV 256 = 0) OR (typ.id MOD 4 IN {0, 3}) THEN	(* scalar *)
+				IF (kind = 10) & ((S.VAL(INTEGER, typ) = 8) OR (S.VAL(INTEGER, typ) = 10)) THEN	(* 64 bit *)
+					DEC(n); PUSH(par[n])	(* push hi word *)
+				END;
+				DEC(n); PUSH(par[n])	(* push value/address *)
+			ELSIF typ.id MOD 4 = 1 THEN	(* record *)
+				IF kind # 10 THEN	(* var par *)
+					DEC(n); PUSH(par[n]);	(* push tag *)
+					DEC(n); PUSH(par[n])	(* push address *)
+				ELSE
+					DEC(n, 2);	(* skip tag *)
+					S.GETREG(SP, sp); sp := (sp - typ.size) DIV 4 * 4; S.PUTREG(SP, sp);	(* allocate space *)
+					S.MOVE(par[n], sp, typ.size)	(* copy to stack *)
+				END
+			ELSIF typ.size = 0 THEN	(* open array *)
+				size := typ.id DIV 16 MOD 16;	(* number of open dimensions *)
+				WHILE size > 0 DO
+					DEC(size); DEC(n); PUSH(par[n])	(* push length *)
+				END;
+				DEC(n); PUSH(par[n])	(* push address *)
+			ELSE	(* fix array *)
+				IF kind # 10 THEN	(* var par *)
+					DEC(n, 2); PUSH(par[n])	(* push address *)
+				ELSE
+					DEC(n); size := par[n]; DEC(n);
+					S.GETREG(SP, sp); sp := (sp - size) DIV 4 * 4; S.PUTREG(SP, sp);	(* allocate space *)
+					S.MOVE(par[n], sp, size)	(* copy to stack *)
+				END
+			END
+		END;
+		ASSERT(n = 0);
+		IF S.VAL(INTEGER, sig.retStruct) = 7 THEN	(* shortreal *)
+			CALL(adr);
+			RETURN S.VAL(INTEGER, SHORT(RETR()))	(* return value in fpu register *)
+		ELSIF S.VAL(INTEGER, sig.retStruct) = 8 THEN	(* real *)
+			CALL(adr); r := RETR(); 
+			RETURN S.VAL(LONGINT, r)	(* return value in fpu register *)
+		ELSE
+			CALL(adr);
+			RETURN RETI()	(* return value in integer registers *)
+		END
+	END Call;
+
+	(* -------------------- reference information (portable) --------------------- *)
+
+	PROCEDURE RefCh (VAR ref: INTEGER; VAR ch: SHORTCHAR);
+	BEGIN
+		S.GET(ref, ch); INC(ref)
+	END RefCh;
+
+	PROCEDURE RefNum (VAR ref: INTEGER; VAR x: INTEGER);
+		VAR s, n: INTEGER; ch: SHORTCHAR;
+	BEGIN
+		s := 0; n := 0; RefCh(ref, ch);
+		WHILE ORD(ch) >= 128 DO INC(n, ASH(ORD(ch) - 128, s) ); INC(s, 7); RefCh(ref, ch) END;
+		x := n + ASH(ORD(ch) MOD 64 - ORD(ch) DIV 64 * 64, s)
+	END RefNum;
+
+	PROCEDURE RefName (VAR ref: INTEGER; VAR n: Name);
+		VAR i: INTEGER; ch: SHORTCHAR;
+	BEGIN
+		i := 0; RefCh(ref, ch);
+		WHILE ch # 0X DO n[i] := ch; INC(i); RefCh(ref, ch) END;
+		n[i] := 0X
+	END RefName;
+
+	PROCEDURE GetRefProc* (VAR ref: INTEGER; VAR adr: INTEGER; VAR name: Name);
+		VAR ch: SHORTCHAR;
+	BEGIN
+		S.GET(ref, ch);
+		WHILE ch >= 0FDX DO	(* skip variables *)
+			INC(ref); RefCh(ref, ch);
+			IF ch = 10X THEN INC(ref, 4) END;
+			RefNum(ref, adr); RefName(ref, name); S.GET(ref, ch)
+		END;
+		WHILE (ch > 0X) & (ch < 0FCX) DO	(* skip source refs *)
+			INC(ref); RefNum(ref, adr); S.GET(ref, ch)
+		END;
+		IF ch = 0FCX THEN INC(ref); RefNum(ref, adr); RefName(ref, name)
+		ELSE adr := 0
+		END
+	END GetRefProc;
+
+	PROCEDURE GetRefVar* (VAR ref: INTEGER; VAR mode, form: SHORTCHAR; VAR desc: Type;
+																VAR adr: INTEGER; VAR name: Name);
+	BEGIN
+		S.GET(ref, mode); desc := NIL;
+		IF mode >= 0FDX THEN
+			mode := SHORT(CHR(ORD(mode) - 0FCH));
+			INC(ref); RefCh(ref, form);
+			IF form = 10X THEN
+				S.GET(ref, desc); INC(ref, 4); form := SHORT(CHR(16 + desc.id MOD 4))
+			END;
+			RefNum(ref, adr); RefName(ref, name)
+		ELSE
+			mode := 0X; form := 0X; adr := 0
+		END
+	END GetRefVar;
+
+	PROCEDURE SourcePos* (mod: Module; codePos: INTEGER): INTEGER;
+		VAR ref, pos, ad, d: INTEGER; ch: SHORTCHAR; name: Name;
+	BEGIN
+		ref := mod.refs; pos := 0; ad := 0; S.GET(ref, ch);
+		WHILE ch # 0X DO
+			WHILE (ch > 0X) & (ch < 0FCX) DO
+				INC(ad, ORD(ch)); INC(ref); RefNum(ref, d);
+				IF ad > codePos THEN RETURN pos END;
+				INC(pos, d); S.GET(ref, ch) 
+			END;
+			IF ch = 0FCX THEN INC(ref); RefNum(ref, d); RefName(ref, name); S.GET(ref, ch) END;
+			WHILE ch >= 0FDX DO	(* skip variables *)
+				INC(ref); RefCh(ref, ch);
+				IF ch = 10X THEN INC(ref, 4) END;
+				RefNum(ref, d); RefName(ref, name); S.GET(ref, ch)
+			END
+		END;
+		RETURN -1
+	END SourcePos;
+
+	(* -------------------- dynamic link libraries --------------------- *)
+
+	PROCEDURE LoadDll* (IN name: ARRAY OF SHORTCHAR; VAR ok: BOOLEAN);
+		VAR h: Dl.HANDLE;
+	BEGIN
+		ok := FALSE;
+		h := Dl.dlopen(name, Dl.RTLD_LAZY +  Dl.RTLD_GLOBAL);
+		IF h # Dl.NULL THEN ok := TRUE END
+	END LoadDll;
+	
+	PROCEDURE ThisDllObj* (mode, fprint: INTEGER; IN dll, name: ARRAY OF SHORTCHAR): INTEGER;
+		VAR ad: INTEGER; h: Dl.HANDLE;
+	BEGIN
+		ad := 0;
+		IF mode IN {mVar, mProc} THEN
+			h := Dl.dlopen(dll, Dl.RTLD_LAZY+  Dl.RTLD_GLOBAL);
+			IF h # Dl.NULL THEN
+				ad := Dl.dlsym(h, name);
+			END
+		END;
+		RETURN ad
+	END ThisDllObj;
+
+	(* -------------------- garbage collector (portable) --------------------- *)
+
+	PROCEDURE Mark (this: Block);
+		VAR father, son: Block; tag: Type; flag, offset, actual: INTEGER;
+	BEGIN
+		IF ~ODD(S.VAL(INTEGER, this.tag)) THEN
+			father := NIL;
+			LOOP
+				INC(S.VAL(INTEGER, this.tag));
+				flag := S.VAL(INTEGER, this.tag) MOD 4;
+				tag := S.VAL(Type, S.VAL(INTEGER, this.tag) - flag);
+				IF flag >= 2 THEN actual := this.first; this.actual := actual
+				ELSE actual := S.ADR(this.last)
+				END;
+				LOOP
+					offset := tag.ptroffs[0];
+					IF offset < 0 THEN
+						INC(S.VAL(INTEGER, tag), offset + 4);	(* restore tag *)
+						IF (flag >= 2) & (actual < this.last) & (offset < -4) THEN	(* next array element *)
+							INC(actual, tag.size); this.actual := actual
+						ELSE	(* up *)
+							this.tag := S.VAL(Type, S.VAL(INTEGER, tag) + flag);
+							IF father = NIL THEN RETURN END;
+							son := this; this := father;
+							flag := S.VAL(INTEGER, this.tag) MOD 4;
+							tag := S.VAL(Type, S.VAL(INTEGER, this.tag) - flag);
+							offset := tag.ptroffs[0];
+							IF flag >= 2 THEN actual := this.actual ELSE actual := S.ADR(this.last) END;
+							S.GET(actual + offset, father); S.PUT(actual + offset, S.ADR(son.last));
+							INC(S.VAL(INTEGER, tag), 4)
+						END
+					ELSE
+						S.GET(actual + offset, son);
+						IF son # NIL THEN
+							DEC(S.VAL(INTEGER, son), 4);
+							IF ~ODD(S.VAL(INTEGER, son.tag)) THEN	(* down *)
+								this.tag := S.VAL(Type, S.VAL(INTEGER, tag) + flag);
+								S.PUT(actual + offset, father); father := this; this := son;
+								EXIT
+							END
+						END;
+						INC(S.VAL(INTEGER, tag), 4)
+					END
+				END
+			END
+		END
+	END Mark;
+
+	PROCEDURE MarkGlobals;
+		VAR m: Module; i, p: INTEGER;
+	BEGIN
+		m := modList;
+		WHILE m # NIL DO
+			IF m.refcnt >= 0 THEN
+				i := 0;
+				WHILE i < m.nofptrs DO
+					S.GET(m.varBase + m.ptrs[i], p); INC(i);
+					IF p # 0 THEN Mark(S.VAL(Block, p - 4)) END
+				END
+			END;
+			m := m.next
+		END
+	END MarkGlobals;
+
+(*  This is the specification for the code procedure following below:
+
+	PROCEDURE Next (b: Block): Block;	(* next block in same cluster *)
+		VAR size: INTEGER;
+	BEGIN
+		S.GET(S.VAL(INTEGER, b.tag) DIV 4 * 4, size);
+		IF ODD(S.VAL(INTEGER, b.tag) DIV 2) THEN INC(size, b.last - S.ADR(b.last)) END;
+		RETURN S.VAL(Block, S.VAL(INTEGER, b) + (size + 19) DIV 16 * 16)
+	END Next;
+
+*)
+	PROCEDURE [code] Next (b: Block): Block	(* next block in same cluster *)
+	(*
+		MOV	ECX,[EAX]	b.tag
+		AND	CL,0FCH	b.tag DIV * 4
+		MOV	ECX,[ECX]	size
+		TESTB	[EAX],02H	ODD(b.tag DIV 2)
+		JE	L1
+		ADD	ECX,[EAX,4]	size + b.last
+		SUB	ECX,EAX
+		SUB	ECX,4	size + b.last - ADR(b.last)
+		L1:
+		ADD	ECX,19	size + 19
+		AND	CL,0F0H	(size + 19) DIV 16 * 16
+		ADD	EAX,ECX	b + size
+	*)
+	08BH, 008H,
+	080H, 0E1H, 0FCH,
+	08BH, 009H,
+	0F6H, 000H, 002H,
+	074H, 008H,
+	003H, 048H, 004H,
+	029H, 0C1H,
+	083H, 0E9H, 004H,
+	083H, 0C1H, 013H,
+	080H, 0E1H, 0F0H,
+	001H, 0C8H;
+
+	PROCEDURE CheckCandidates;
+	(* pre: nofcand > 0 *)
+		VAR i, j, h, p, end: INTEGER; c: Cluster; blk, next: Block;
+	BEGIN
+		(* sort candidates (shellsort) *)
+		h := 1; REPEAT h := h*3 + 1 UNTIL h > nofcand;
+		REPEAT h := h DIV 3; i := h;
+			WHILE i < nofcand DO p := candidates[i]; j := i;
+				WHILE (j >= h) & (candidates[j-h] > p) DO
+					candidates[j] := candidates[j-h]; j := j-h
+				END;
+				candidates[j] := p; INC(i)
+			END
+		UNTIL h = 1;
+		(* sweep *)
+		c := root; i := 0;
+		WHILE c # NIL DO
+			blk := S.VAL(Block, S.VAL(INTEGER, c) + 12);
+			end := S.VAL(INTEGER, blk) + (c.size - 12) DIV 16 * 16;
+			WHILE candidates[i] < S.VAL(INTEGER, blk) DO
+				INC(i);
+				IF i = nofcand THEN RETURN END
+			END;
+			WHILE S.VAL(INTEGER, blk) < end DO
+				next := Next(blk);
+				IF candidates[i] < S.VAL(INTEGER, next) THEN
+					IF (S.VAL(INTEGER, blk.tag) # S.ADR(blk.last))	(* not a free block *)
+							& (~strictStackSweep OR (candidates[i] = S.ADR(blk.last))) THEN
+						Mark(blk)
+					END;
+					REPEAT
+						INC(i);
+						IF i = nofcand THEN RETURN END
+					UNTIL candidates[i] >= S.VAL(INTEGER, next)
+				END;
+				IF (S.VAL(INTEGER, blk.tag) MOD 4 = 0) & (S.VAL(INTEGER, blk.tag) # S.ADR(blk.last))
+						& (blk.tag.base[0] = NIL) & (blk.actual > 0) THEN	(* referenced interface record *)
+					Mark(blk)
+				END;
+				blk := next
+			END;
+			c := c.next
+		END
+	END CheckCandidates;
+
+	PROCEDURE MarkLocals;
+		VAR sp, p, min, max: INTEGER; c: Cluster;
+	BEGIN
+		S.GETREG(FP, sp); nofcand := 0; c := root;
+		WHILE c.next # NIL DO c := c.next END;
+		min := S.VAL(INTEGER, root); max := S.VAL(INTEGER, c) + c.size;
+		WHILE sp < baseStack DO
+			S.GET(sp, p);
+			IF (p > min) & (p < max) & (~strictStackSweep OR (p MOD 16 = 0)) THEN
+				candidates[nofcand] := p; INC(nofcand);
+				IF nofcand = LEN(candidates) - 1 THEN CheckCandidates; nofcand := 0 END
+			END;
+			INC(sp, 4)
+		END;
+		candidates[nofcand] := max; INC(nofcand);	(* ensure complete scan for interface mark*)
+		IF nofcand > 0 THEN CheckCandidates END
+	END MarkLocals;
+
+	PROCEDURE MarkFinObj;
+		VAR f: FList;
+	BEGIN
+		wouldFinalize := FALSE;
+		f := finalizers;
+		WHILE f # NIL DO
+			IF ~ODD(S.VAL(INTEGER, f.blk.tag)) THEN wouldFinalize := TRUE END;
+			Mark(f.blk);
+			f := f.next
+		END;
+		f := hotFinalizers;
+		WHILE f # NIL DO IF ~ODD(S.VAL(INTEGER, f.blk.tag)) THEN wouldFinalize := TRUE END;
+			Mark(f.blk);
+			f := f.next
+		END
+	END MarkFinObj;
+
+	PROCEDURE CheckFinalizers;
+		VAR f, g, h, k: FList;
+	BEGIN
+		f := finalizers; g := NIL;
+		IF hotFinalizers = NIL THEN k := NIL
+		ELSE
+			k := hotFinalizers;
+			WHILE k.next # NIL DO k := k.next END
+		END;
+		WHILE f # NIL DO
+			h := f; f := f.next;
+			IF ~ODD(S.VAL(INTEGER, h.blk.tag)) THEN
+				IF g = NIL THEN finalizers := f ELSE g.next := f END;
+				IF k = NIL THEN hotFinalizers := h ELSE k.next := h END;
+				k := h; h.next := NIL
+			ELSE g := h
+			END
+		END;
+		h := hotFinalizers;
+		WHILE h # NIL DO Mark(h.blk); h := h.next END
+	END CheckFinalizers;
+
+	PROCEDURE ExecFinalizer (a, b, c: INTEGER);
+		VAR f: FList; fin: PROCEDURE(this: ANYPTR);
+	BEGIN
+		f := S.VAL(FList, a);
+		IF f.aiptr THEN (* ArrFinalizer(S.VAL(ANYPTR, S.ADR(f.blk.last))) *)
+		ELSE
+			S.GET(S.VAL(INTEGER, f.blk.tag) - 4, fin);	(* method 0 *)
+			IF (fin # NIL) & (f.blk.tag.mod.refcnt >= 0) THEN fin(S.VAL(ANYPTR, S.ADR(f.blk.last))) END;
+(*
+			IF f.iptr THEN RecFinalizer(S.VAL(ANYPTR, S.ADR(f.blk.last))) END
+*)
+		END
+	END ExecFinalizer;
+
+	PROCEDURE^ Try* (h: TryHandler; a, b, c: INTEGER);	(* COMPILER DEPENDENT *)
+
+	PROCEDURE CallFinalizers;
+		VAR f: FList;
+	BEGIN
+		WHILE hotFinalizers # NIL DO
+			f := hotFinalizers; hotFinalizers := hotFinalizers.next;
+			Try(ExecFinalizer, S.VAL(INTEGER, f), 0, 0)
+		END;
+		wouldFinalize := FALSE
+	END CallFinalizers;
+
+	PROCEDURE Insert (blk: FreeBlock; size: INTEGER);	(* insert block in free list *)
+		VAR i: INTEGER;
+	BEGIN
+		blk.size := size - 4; blk.tag := S.VAL(Type, S.ADR(blk.size));
+		i := MIN(N - 1, (blk.size DIV 16));
+		blk.next := free[i]; free[i] := blk
+	END Insert;
+
+	PROCEDURE Sweep (dealloc: BOOLEAN);
+		VAR cluster, last, c: Cluster; blk, next: Block; fblk, b, t: FreeBlock; end, i: INTEGER;
+	BEGIN
+		cluster := root; last := NIL; allocated := 0;
+		i := N;
+		REPEAT DEC(i); free[i] := sentinel UNTIL i = 0;
+		WHILE cluster # NIL DO
+			blk := S.VAL(Block, S.VAL(INTEGER, cluster) + 12);
+			end := S.VAL(INTEGER, blk) + (cluster.size - 12) DIV 16 * 16;
+			fblk := NIL;
+			WHILE S.VAL(INTEGER, blk) < end DO
+				next := Next(blk);
+				IF ODD(S.VAL(INTEGER, blk.tag)) THEN
+					IF fblk # NIL THEN
+						Insert(fblk, S.VAL(INTEGER, blk) - S.VAL(INTEGER, fblk));
+						fblk := NIL
+					END;
+					DEC(S.VAL(INTEGER, blk.tag));	(* unmark *)
+					INC(allocated, S.VAL(INTEGER, next) - S.VAL(INTEGER, blk))
+				ELSIF fblk = NIL THEN
+					fblk := S.VAL(FreeBlock, blk)
+				END;
+				blk := next
+			END;
+			IF dealloc & (S.VAL(INTEGER, fblk) = S.VAL(INTEGER, cluster) + 12) THEN	(* deallocate cluster *)
+				c := cluster; cluster := cluster.next;
+				IF last = NIL THEN root := cluster ELSE last.next := cluster END;
+				FreeHeapMem(c)
+			ELSE
+				IF fblk # NIL THEN Insert(fblk, end - S.VAL(INTEGER, fblk)) END;
+				last := cluster; cluster := cluster.next
+			END
+		END;
+		(* reverse free list *)
+		i := N;
+		REPEAT
+			DEC(i);
+			b := free[i]; fblk := sentinel;
+			WHILE b # sentinel DO t := b; b := t.next; t.next := fblk; fblk := t END;
+			free[i] := fblk
+		UNTIL i = 0
+	END Sweep;
+
+	PROCEDURE Collect*;
+	BEGIN
+		IF root # NIL THEN
+			CallFinalizers;	(* trap cleanup *)
+			IF debug & (watcher # NIL) THEN watcher(1) END;
+			MarkGlobals;
+			MarkLocals;
+			CheckFinalizers;
+			Sweep(TRUE);
+			CallFinalizers
+		END
+	END Collect;
+	
+	PROCEDURE FastCollect*;
+	BEGIN
+		IF root # NIL THEN
+			IF debug & (watcher # NIL) THEN watcher(2) END;
+			MarkGlobals;
+			MarkLocals;
+			MarkFinObj;
+			Sweep(FALSE)
+		END
+	END FastCollect;
+
+	PROCEDURE WouldFinalize* (): BOOLEAN;
+	BEGIN
+		RETURN wouldFinalize
+	END WouldFinalize;
+
+	(* --------------------- memory allocation (portable) -------------------- *)
+
+	PROCEDURE OldBlock (size: INTEGER): FreeBlock;	(* size MOD 16 = 0 *)
+		VAR b, l: FreeBlock; s, i: INTEGER;
+	BEGIN
+		IF debug & (watcher # NIL) THEN watcher(3) END;
+		s := size - 4;
+		i := MIN(N - 1, s DIV 16);
+		WHILE (i # N - 1) & (free[i] = sentinel) DO INC(i) END;
+		b := free[i]; l := NIL;
+		WHILE b.size < s DO l := b; b := b.next END;
+		IF b # sentinel THEN
+			IF l = NIL THEN free[i] := b.next ELSE l.next := b.next END
+		ELSE b := NIL
+		END;
+		RETURN b
+	END OldBlock;
+
+	PROCEDURE LastBlock (limit: INTEGER): FreeBlock;	(* size MOD 16 = 0 *)
+		VAR b, l: FreeBlock; s, i: INTEGER;
+	BEGIN
+		s := limit - 4;
+		i := 0;
+		REPEAT
+			b := free[i]; l := NIL;
+			WHILE (b # sentinel) & (S.VAL(INTEGER, b) + b.size # s) DO l := b; b := b.next END;
+			IF b # sentinel THEN
+				IF l = NIL THEN free[i] := b.next ELSE l.next := b.next END
+			ELSE b := NIL
+			END;
+			INC(i)
+		UNTIL (b # NIL) OR (i = N);
+		RETURN b
+	END LastBlock;
+
+	PROCEDURE NewBlock (size: INTEGER): Block;
+		VAR tsize, a, s: INTEGER; b: FreeBlock; new, c: Cluster; r: Reducer;
+	BEGIN
+		ASSERT(size>=0,20);
+		IF size >7FFFFFECH THEN RETURN NIL END; (*20120822 Marc*)
+		tsize := (size + 19) DIV 16 * 16;
+		b := OldBlock(tsize);	(* 1) search for free block *)
+		IF b = NIL THEN
+			FastCollect; b := OldBlock(tsize);	(* 2) collect *)
+			IF b = NIL THEN
+				Collect; b := OldBlock(tsize);	(* 2a) fully collect *)
+			END;
+			IF b = NIL THEN
+				AllocHeapMem(tsize + 12, new);	(* 3) allocate new cluster *)
+				IF new # NIL THEN
+					IF (root = NIL) OR (S.VAL(INTEGER, new) < S.VAL(INTEGER, root)) THEN
+						new.next := root; root := new
+					ELSE
+						c := root;
+						WHILE (c.next # NIL) & (S.VAL(INTEGER, new) > S.VAL(INTEGER, c.next)) DO c := c.next END;
+						new.next := c.next; c.next := new
+					END;
+					b := S.VAL(FreeBlock, S.VAL(INTEGER, new) + 12);
+					b.size := (new.size - 12) DIV 16 * 16 - 4
+				ELSE
+					RETURN NIL	(* 4) give up *)
+				END
+			END
+		END;
+		(* b # NIL *)
+		a := b.size + 4 - tsize;
+		IF a > 0 THEN Insert(S.VAL(FreeBlock, S.VAL(INTEGER, b) + tsize), a) END;
+		IF size > 0 THEN Erase(S.ADR(b.size), (size + 3) DIV 4) END;
+		INC(allocated, tsize);
+		RETURN S.VAL(Block, b)
+	END NewBlock;
+
+	PROCEDURE Allocated* (): INTEGER;
+	BEGIN
+		RETURN allocated
+	END Allocated;
+
+	PROCEDURE Used* (): INTEGER;
+	BEGIN
+		RETURN used
+	END Used;
+
+	PROCEDURE Root* (): INTEGER;
+	BEGIN
+		RETURN S.VAL(INTEGER, root)
+	END Root;
+
+
+	(* -------------------- Trap Handling --------------------- *)
+
+	PROCEDURE^ InitFpu;
+
+	PROCEDURE Start* (code: Command);
+	BEGIN
+		restart := code;
+		S.GETREG(SP, baseStack);	(* save base stack *)
+		code()
+	END Start;
+
+	PROCEDURE Quit* (exitCode: INTEGER);
+		VAR m: Module; term: Command; t: BOOLEAN;
+			res: INTEGER;
+	BEGIN
+		trapViewer := NIL; trapChecker := NIL; restart := NIL;
+		t := terminating; terminating := TRUE; m := modList;
+		WHILE m # NIL DO	(* call terminators *)
+			IF ~static OR ~t THEN
+				term := m.term; m.term := NIL;
+				IF term # NIL THEN term() END
+			END;
+(*
+			ReleaseIPtrs(m);
+*)
+			m := m.next
+		END;
+		CallFinalizers;
+		hotFinalizers := finalizers; finalizers := NIL;
+		CallFinalizers;
+(*
+		IF ~inDll THEN
+			RemoveExcp(excpPtr^);
+			WinApi.ExitProcess(exitCode)	(* never returns *)
+		END
+*)
+
+		res := Libc.fflush(0);
+		Libc.exit(exitCode)
+	END Quit;
+
+	PROCEDURE FatalError* (id: INTEGER; str: ARRAY OF CHAR);
+		VAR res: INTEGER; title: ARRAY 16 OF CHAR; text: ARRAY 256 OF SHORTCHAR;
+	BEGIN
+		title := "Error xy";
+		title[6] := CHR(id DIV 10 + ORD("0"));
+		title[7] := CHR(id MOD 10 + ORD("0"));
+(*
+		res := WinApi.MessageBoxW(0, str, title, {});
+*)
+		text := SHORT(str$);
+		res := MessageBox(title$, SHORT(str), {mbOk});
+(*
+		IF ~inDll THEN RemoveExcp(excpPtr^) END;
+*)
+(*
+		WinApi.ExitProcess(1)
+*)
+		Libc.exit(1)
+		(* never returns *)
+	END FatalError;
+
+	PROCEDURE DefaultTrapViewer;
+		VAR len, ref, end, x, a, b, c: INTEGER; mod: Module;
+			name: Name; out: ARRAY 1024 OF SHORTCHAR;
+
+		PROCEDURE WriteString (s: ARRAY OF SHORTCHAR);
+			VAR i: INTEGER;
+		BEGIN
+			i := 0;
+			WHILE (len < LEN(out) - 1) & (s[i] # 0X) DO out[len] := s[i]; INC(i); INC(len) END
+		END WriteString;
+
+		PROCEDURE WriteHex (x, n: INTEGER);
+			VAR i, y: INTEGER;
+		BEGIN
+			IF len + n < LEN(out) THEN
+				i := len + n - 1;
+				WHILE i >= len DO
+					y := x MOD 16; x := x DIV 16;
+					IF y > 9 THEN y := y + (ORD("A") - ORD("0") - 10) END;
+					out[i] := SHORT(CHR(y + ORD("0"))); DEC(i)
+				END;
+				INC(len, n)
+			END
+		END WriteHex;
+
+		PROCEDURE WriteLn;
+		BEGIN
+			IF len < LEN(out) - 1 THEN out[len] := 0AX (* 0DX on Windows *); INC(len) END
+		END WriteLn;
+
+	BEGIN
+		len := 0;
+		IF err = 129 THEN WriteString("invalid with")
+		ELSIF err = 130 THEN WriteString("invalid case")
+		ELSIF err = 131 THEN WriteString("function without return")
+		ELSIF err = 132 THEN WriteString("type guard")
+		ELSIF err = 133 THEN WriteString("implied type guard")
+		ELSIF err = 134 THEN WriteString("value out of range")
+		ELSIF err = 135 THEN WriteString("index out of range")
+		ELSIF err = 136 THEN WriteString("string too long")
+		ELSIF err = 137 THEN WriteString("stack overflow")
+		ELSIF err = 138 THEN WriteString("integer overflow")
+		ELSIF err = 139 THEN WriteString("division by zero")
+		ELSIF err = 140 THEN WriteString("infinite real result")
+		ELSIF err = 141 THEN WriteString("real underflow")
+		ELSIF err = 142 THEN WriteString("real overflow")
+		ELSIF err = 143 THEN WriteString("undefined real result")
+		ELSIF err = 200 THEN WriteString("keyboard interrupt")
+		ELSIF err = 202 THEN WriteString("illegal instruction:  ");
+			WriteHex(val, 4)
+		ELSIF err = 203 THEN WriteString("illegal memory read [ad = ");
+			WriteHex(val, 8); WriteString("]")
+		ELSIF err = 204 THEN WriteString("illegal memory write [ad = ");
+			WriteHex(val, 8); WriteString("]")
+		ELSIF err = 205 THEN WriteString("illegal execution [ad = ");
+			WriteHex(val, 8); WriteString("]")
+		ELSIF err < 0 THEN WriteString("exception #"); WriteHex(-err, 2)
+		ELSE err := err DIV 100 * 256 + err DIV 10 MOD 10 * 16 + err MOD 10;
+			WriteString("trap #"); WriteHex(err, 3)
+		END;
+		a := pc; b := fp; c := 12;
+		REPEAT
+			WriteLn; WriteString("- ");
+			mod := modList;
+			WHILE (mod # NIL) & ((a < mod.code) OR (a >= mod.code + mod.csize)) DO mod := mod.next END;
+			IF mod # NIL THEN
+				DEC(a, mod.code);
+				IF mod.refcnt >= 0 THEN
+					WriteString(mod.name); ref := mod.refs;
+					REPEAT GetRefProc(ref, end, name) UNTIL (end = 0) OR (a < end);
+					IF a < end THEN
+						WriteString("."); WriteString(name)
+					END
+				ELSE
+					WriteString("("); WriteString(mod.name); WriteString(")")
+				END;
+				WriteString("  ")
+			END;
+			WriteString("(pc="); WriteHex(a, 8);
+			WriteString(", fp="); WriteHex(b, 8); WriteString(")");
+			IF (b >= sp) & (b < stack) THEN
+				S.GET(b+4, a);	(* stacked pc *)
+				S.GET(b, b);	(* dynamic link *)
+				DEC(c)
+			ELSE c := 0
+			END
+		UNTIL c = 0;
+		out[len] := 0X;
+		x := MessageBox("BlackBox", out$, {mbOk})
+	END DefaultTrapViewer;
+
+	PROCEDURE TrapCleanup;
+		VAR t: TrapCleaner;
+	BEGIN
+		WHILE trapStack # NIL DO
+			t := trapStack; trapStack := trapStack.next; t.Cleanup
+		END;
+		IF (trapChecker # NIL) & (err # 128) THEN trapChecker END
+	END TrapCleanup;
+
+	PROCEDURE SetTrapGuard* (on: BOOLEAN);
+	BEGIN
+		guarded := on
+	END SetTrapGuard;
+
+	PROCEDURE Try* (h: TryHandler; a, b, c: INTEGER);	
+		VAR res: INTEGER; context: Libc.sigjmp_buf; oldContext: POINTER TO Libc.sigjmp_buf;
+	BEGIN
+		oldContext := currentTryContext;
+		res := Libc.sigsetjmp(context, Libc.TRUE);
+		currentTryContext := S.ADR(context);
+		IF res = 0 THEN (* first time around *)
+			h(a, b, c);
+		ELSIF res = trapReturn THEN  (* after a trap *)
+		ELSE
+			HALT(100)
+		END;
+		currentTryContext := oldContext;
+	END Try;
+
+	(* -------------------- Initialization --------------------- *)
+
+	PROCEDURE InitFpu;	(* COMPILER DEPENDENT *)
+		(* could be eliminated, delayed for backward compatibility *)
+		VAR cw: SET;
+	BEGIN
+		FINIT;
+		FSTCW;
+		(* denorm, underflow, precision, zero div, overflow masked *)
+		(* invalid trapped *)
+		(* round to nearest, temp precision *)
+		cw := cw - {0..5, 8..11} + {1, 2, 3, 4, 5, 8, 9};
+		FLDCW
+	END InitFpu;
+
+	PROCEDURE TrapHandler (sig: INTEGER; siginfo: Libc.Ptrsiginfo_t; context: Libc.Ptrucontext_t);
+	BEGIN
+	(*
+		S.GETREG(SP, sp);
+		S.GETREG(FP, fp);
+	*)
+		stack := baseStack;
+
+		sp := context.uc_mcontext.gregs[7]; (* TODO: is the stack pointer really stored in register 7? *)
+		fp := context.uc_mcontext.gregs[6]; (* TODO: is the frame pointer really stored in register 6? *)
+		pc := context.uc_mcontext.gregs[14]; (* TODO: is the pc really stored in register 14? *)
+		val := siginfo.si_addr;
+
+	(*
+		Int(sig); Int(siginfo.si_signo); Int(siginfo.si_code); Int(siginfo.si_errno);
+		Int(siginfo.si_status); Int(siginfo.si_value); Int(siginfo.si_int);
+	*)
+		err := sig;
+		IF trapped THEN DefaultTrapViewer END;
+		CASE sig OF
+			Libc.SIGINT: 
+				err := 200 (* Interrupt (ANSI). *)
+			| Libc.SIGILL: (* Illegal instruction (ANSI). *)
+				err := 202; val := 0;
+				IF IsReadable(pc, pc + 4) THEN
+					S.GET(pc, val);
+					IF val MOD 100H = 8DH THEN	(* lea reg,reg *)
+						IF val DIV 100H MOD 100H = 0F0H THEN
+							err := val DIV 10000H MOD 100H	(* trap *)
+						ELSIF val DIV 1000H MOD 10H = 0EH THEN
+							err := 128 + val DIV 100H MOD 10H	(* run time error *)
+						END
+					END
+				END
+			| Libc.SIGFPE: 
+				CASE siginfo.si_code OF
+					0: (* TODO: ?????? *)
+						IF siginfo.si_int = 8 THEN
+							err := 139
+						ELSIF siginfo.si_int = 0 THEN
+							err := 143
+						END
+					| Libc.FPE_INTDIV: err := 139 (* Integer divide by zero.  *)
+					| Libc.FPE_INTOVF: err := 138 (* Integer overflow.  *)
+					| Libc.FPE_FLTDIV: err := 140 (* Floating point divide by zero.  *)
+					| Libc.FPE_FLTOVF: err := 142 (* Floating point overflow.  *)
+					| Libc.FPE_FLTUND: err := 141 (* Floating point underflow.  *)
+					| Libc.FPE_FLTRES: err := 143 (* Floating point inexact result.  *)
+					| Libc.FPE_FLTINV: err := 143 (* Floating point invalid operation.  *)
+					| Libc.FPE_FLTSUB: err := 134 (* Subscript out of range.  *)
+				ELSE
+				END
+			| Libc.SIGSEGV: (* Segmentation violation (ANSI). *) 
+				err := 203
+		ELSE
+		END;
+		INC(trapCount);
+		InitFpu;
+		TrapCleanup;
+		IF err # 128 THEN
+			IF (trapViewer = NIL) OR trapped THEN
+				DefaultTrapViewer
+			ELSE
+				trapped := TRUE;
+				trapViewer();
+				trapped := FALSE
+			END
+		END;
+		IF currentTryContext # NIL THEN (* Try failed *)
+			Libc.siglongjmp(currentTryContext, trapReturn)
+		ELSE
+			IF restart # NIL THEN (* Start failed *)
+				Libc.siglongjmp(loopContext, trapReturn)
+			END;
+			Quit(1);
+		END;
+		trapped := FALSE
+	END TrapHandler;
+
+	PROCEDURE InstallSignals*;
+		(* CONST
+			sigStackSize = Libc.SIGSTKSZ; *)
+		VAR sa, old: Libc.sigaction_t; res, i: INTEGER;
+			(* sigstk: Libc.sigaltstack_t; *)
+	BEGIN
+(* Linux: TODO
+		(* A. V. Shiryaev: Set alternative stack on which signals are to be processed *)
+			sigstk.ss_sp := Libc.calloc(1, sigStackSize);
+			IF sigstk.ss_sp # Libc.NULL THEN
+				sigstk.ss_size := sigStackSize;
+				sigstk.ss_flags := 0;
+				res := Libc.sigaltstack(sigstk, NIL);
+				IF res # 0 THEN Msg("ERROR: Kernel.InstallSignals: sigaltstack failed!");
+					Libc.exit(1)
+				END
+			ELSE Msg("ERROR: malloc(SIGSTKSIZE) failed");
+				Libc.exit(1)
+			END;
+*)
+
+		sa.sa_sigaction := TrapHandler;
+(*
+		res := LinLibc.sigemptyset(S.ADR(sa.sa_mask));
+*)
+		res := Libc.sigfillset(S.ADR(sa.sa_mask));
+		sa.sa_flags := (* Libc.SA_ONSTACK + *) Libc.SA_SIGINFO; (* TrapHandler takes three arguments *)
+		(*
+		IF LinLibc.sigaction(LinLibc.SIGINT, sa, old) # 0 THEN Msg("failed to install SIGINT") END;
+		IF LinLibc.sigaction(LinLibc.SIGILL, sa, old) # 0 THEN Msg("failed to install SIGILL") END;
+		IF LinLibc.sigaction(LinLibc.SIGFPE, sa, old) # 0 THEN Msg("failed to install SIGFPE") END;
+		IF LinLibc.sigaction(LinLibc.SIGSEGV, sa, old) # 0 THEN Msg("failed to install SIGSEGV") END;
+		IF LinLibc.sigaction(LinLibc.SIGPIPE, sa, old) # 0 THEN Msg("failed to install SIGPIPE") END;
+		IF LinLibc.sigaction(LinLibc.SIGTERM, sa, old) # 0 THEN Msg("failed to install SIGTERM") END;
+		*)
+		(* respond to all possible signals *)
+		FOR i := 1 TO Libc._NSIG - 1 DO 
+			IF (i # Libc.SIGKILL)
+				& (i # Libc.SIGSTOP)
+				& (i # Libc.SIGWINCH)
+			THEN
+				IF Libc.sigaction(i, sa, old) # 0 THEN Msg("failed to install signal"); Int(i) END;
+			END
+		END
+	END InstallSignals;
+
+	PROCEDURE Init;
+		VAR i: INTEGER;
+	BEGIN
+		(* for mmap *)
+			zerofd := Libc.open("/dev/zero", Libc.O_RDWR, {0..8});
+			IF zerofd < 0 THEN
+				Msg("ERROR: Kernel.Init: can not open /dev/zero!");
+				Libc.exit(1)
+			END;
+
+		InstallSignals; (* init exception handling *)
+		currentTryContext := NIL;
+
+		allocated := 0; total := 0; used := 0;
+		sentinelBlock.size := MAX(INTEGER);
+		sentinel := S.ADR(sentinelBlock);
+
+(*
+		S.PUTREG(ML, S.ADR(modList));
+*)
+
+		i := N;
+		REPEAT DEC(i); free[i] := sentinel UNTIL i = 0;
+
+		IF inDll THEN
+(*
+			baseStack := FPageWord(4);	(* begin of stack segment *)
+*)
+		END;
+		InitFpu;
+		IF ~static THEN
+			InitModule(modList);
+			IF ~inDll THEN Quit(1) END
+		END;
+		told := 0; shift := 0
+	END Init;
+
+	PROCEDURE SetCmdLine;
+		VAR i, l: INTEGER;
+	BEGIN
+		l := LEN(cmdLine);
+		cmdLine := bootInfo.argv[0]$;
+		FOR i := 1 TO bootInfo.argc - 1 DO cmdLine := cmdLine + " " + bootInfo.argv[i]END
+	END SetCmdLine;
+	
+	PROCEDURE SetCmdLine2;
+		VAR x: Libc.PtrSTR;
+	BEGIN
+		x := Libc.getenv("CMDLINE");
+		IF x # NIL THEN
+			cmdLine := x$
+		END
+	END SetCmdLine2;
+
+BEGIN
+	IF modList = NIL THEN	(* only once *)
+		IF bootInfo # NIL THEN
+			modList := bootInfo.modList; (* boot loader initializes the bootInfo struct *)
+			S.GETREG(SP, baseStack); (* TODO: Check that this is ok. *)
+			SetCmdLine
+		ELSE
+			S.GETREG(ML, modList);	(* linker loads module list to BX *)
+			S.GETREG(SP, baseStack);
+			SetCmdLine2
+		END;
+		static := init IN modList.opts;
+		inDll := dll IN modList.opts;
+		Init
+	END
+CLOSE
+	IF ~terminating THEN
+		terminating := TRUE;
+		Quit(0)
+	END
+END Kernel.

+ 0 - 0
BlackBox/Lin/Mod/Kernel_so_init.odc → BlackBox/Linux/Lin/Mod/Kernel_so_init.odc


+ 0 - 0
BlackBox/Lin/Mod/Kernel_so_init.txt → BlackBox/Linux/Lin/Mod/Kernel_so_init.txt


BIN
BlackBox/Linux/Lin/Mod/Libc.odc


+ 452 - 0
BlackBox/Linux/Lin/Mod/Libc.txt

@@ -0,0 +1,452 @@
+MODULE LinLibc ["libc.so.6"];
+
+	(* THIS IS TEXT COPY OF Libc.odc *)
+	(* DO NOT EDIT *)
+
+	IMPORT SYSTEM;
+	
+	CONST
+		NULL* = 0H;
+		TRUE* = 1;
+		FALSE* = 0;
+		
+		(* file constants *)
+		SEEK_SET* = 0;
+		SEEK_CUR* = 1;
+		SEEK_END* = 2;
+		NAME_MAX* = 256;
+		
+		(* The value of CLOCKS_PER_SEC is required to be 1 million on all   XSI-conformant systems.*)
+		CLOCKS_PER_SECOND* = 1000000; 
+		
+		(* temp directory defined in stdio.h *)
+		P_tmpdir* = "/tmp";
+		
+		(* signal constants *)	(* Fake signal functions.  *)
+		SIG_ERR* = -1; 	(* Error return.  *)
+		SIG_DFL* = 0;   	(* Default action.  *)
+		SIG_IGN* = 1;    	(* Ignore signal.  *)
+		SIG_HOLD* = 2;	(* Add signal to hold mask.  *)
+		
+		(* Signals.  *)
+		SIGHUP* = 1;	(* Hangup (POSIX).  *)
+		SIGINT* = 2;	(* Interrupt (ANSI).  *)
+		SIGQUIT* = 3;	(* Quit (POSIX).  *)
+		SIGILL* = 4;	(* Illegal instruction (ANSI).  *)
+		SIGTRAP* = 5;	(* Trace trap (POSIX).  *)
+		SIGABRT* = 6;	(* Abort (ANSI).  *)
+		SIGIOT* = 6;	(* IOT trap (4.2 BSD).  *)
+		SIGBUS* = 7;	(* BUS error (4.2 BSD).  *)
+		SIGFPE* = 8;	(* Floating-point exception (ANSI).  *)
+		SIGKILL* = 9;	(* Kill, unblockable (POSIX).  *)
+		SIGUSR1* = 10;	(* User-defined signal 1 (POSIX).  *)
+		SIGSEGV* = 11;	(* Segmentation violation (ANSI).  *)
+		SIGUSR2* = 12;	(* User-defined signal 2 (POSIX).  *)
+		SIGPIPE* = 13;	(* Broken pipe (POSIX).  *)
+		SIGALRM* = 14;	(* Alarm clock (POSIX).  *)
+		SIGTERM* = 15;	(* Termination (ANSI).  *)
+		SIGSTKFLT* = 16;	(* Stack fault.  *)
+		SIGCHLD* = 17;	(* Child status has changed (POSIX).  *)
+		SIGCLD* = SIGCHLD;	(* Same as SIGCHLD (System V).  *)
+		SIGCONT* = 18;	(* Continue (POSIX).  *)
+		SIGSTOP* = 19;	(* Stop, unblockable (POSIX).  *)
+		SIGTSTP* = 20;	(* Keyboard stop (POSIX).  *)
+		SIGTTIN* = 21;	(* Background read from tty (POSIX).  *)
+		SIGTTOU* = 22;	(* Background write to tty (POSIX).  *)
+		SIGURG* = 23;	(* Urgent condition on socket (4.2 BSD).  *)
+		SIGXCPU* = 24;	(* CPU limit exceeded (4.2 BSD).  *)
+		SIGXFSZ* = 25;	(* File size limit exceeded (4.2 BSD).  *)
+		SIGVTALRM* =26;	(* Virtual alarm clock (4.2 BSD).  *)
+		SIGPROF* = 27;	(* Profiling alarm clock (4.2 BSD).  *)
+		SIGWINCH* = 28;	(* Window size change (4.3 BSD, Sun).  *)
+		SIGIO* = 29;	(* I/O now possible (4.2 BSD).  *)
+		SIGPOLL* = SIGIO;	(* Pollable event occurred (System V).  *)
+		SIGPWR* = 30;	(* Power failure restart (System V).  *)
+		SIGSYS* = 31;	(* Bad system call.  *)
+		SIGUNUSED* =31;
+		_NSIG* = 64;	(* Biggest signal number + 1 (including real-time signals).  *)
+		__SIGRTMIN*= 32;
+		__SIGRTMAX*=_NSIG - 1;
+
+		(* Bits in `sa_flags'.  *)
+		SA_NOCLDSTOP* = {0}; 	(* = 1 Don't send SIGCHLD when children stop.  *)
+		SA_NOCLDWAIT* = {1}; 	(* = 2 Don't create zombie on child death.  *)
+		SA_SIGINFO* = {2}; 	(* = 4 Invoke signal-catching function wth three arguments instead of one.  *)
+		SA_ONSTACK* = {27};	(* = 0x08000000 Use signal stack by using `sa_restorer'. *)
+		SA_RESTART* = {28};	(* = 0x10000000 Restart syscall on signal return.  *)
+		SA_NODEFER* = {30};	(* = 0x40000000 Don't automatically block the signal when its handler is being executed. *)
+		SA_RESETHAND* = {31};	(* = 0x80000000 Reset to SIG_DFL on entry to handler.  *)
+		SA_INTERRUPT* = {29};	(* = 0x20000000  Historical no-op.  *)
+		(* Some aliases for the SA_ constants.  *)
+		SA_NOMASK* = SA_NODEFER;
+		SA_ONESHOT* = SA_RESETHAND;
+		SA_STACK* = SA_ONSTACK;
+
+		(* code values for siginfo_t.si_code when sig = SIGFPE *)
+		FPE_INTDIV* = 1;	(* Integer divide by zero.  *)
+		FPE_INTOVF* = 2;	(* Integer overflow.  *)
+		FPE_FLTDIV* = 3;	(* Floating point divide by zero.  *)
+		FPE_FLTOVF* = 4;	(* Floating point overflow.  *)
+		FPE_FLTUND* = 5;	(* Floating point underflow.  *)
+		FPE_FLTRES* =6;	(* Floating point inexact result.  *)
+		FPE_FLTINV* = 7;	(* Floating point invalid operation.  *)
+		FPE_FLTSUB* = 8;	(* Subscript out of range.  *)
+
+		(* possible error constants for errno *)
+		EPERM* = 1;	(* Operation not permitted *)
+		ENOENT* = 2;	(* No such file or directory *)
+		ESRCH* = 3;	(* No such process *)
+		EINTR* = 4;	(* Interrupted system call *)
+		EIO* = 5;	(* I/O error *)
+		ENXIO* = 6;	(* No such device or address *)
+		E2BIG* = 7;	(* Arg list too long *)
+		ENOEXEC* = 8;	(* Exec format error *)
+		EBADF* = 9;	(* Bad file number *)
+		ECHILD* = 10;	(* No child processes *)
+		EAGAIN* = 11;	(* Try again *)
+		ENOMEM* = 12;	(* Out of memory *)
+		EACCES* = 13;	(* Permission denied *)
+		EFAULT* = 14;	(* Bad address *)
+		ENOTBLK* = 15;	(* Block device required *)
+		EBUSY* = 16;	(* Device or resource busy *)
+		EEXIST* = 17;	(* File exists *)
+		EXDEV* = 18;	(* Cross-device link *)
+		ENODEV* = 19;	(* No such device *)
+		ENOTDIR* = 20;	(* Not a directory *)
+		EISDIR* = 21;	(* Is a directory *)
+		EINVAL* = 22;	(* Invalid argument *)
+		ENFILE* = 23;	(* File table overflow *)
+		EMFILE* = 24;	(* Too many open files *)
+		ENOTTY* = 25;	(* Not a typewriter *)
+		ETXTBSY* = 26;	(* Text file busy *)
+		EFBIG* = 27;	(* File too large *)
+		ENOSPC* = 28;	(* No space left on device *)
+		ESPIPE* = 29;	(* Illegal seek *)
+		EROFS* = 30;	(* Read-only file system *)
+		EMLINK* = 31;	(* Too many links *)
+		EPIPE* = 32;	(* Broken pipe *)
+		EDOM* = 33;	(* Math argument out of domain of func *)
+		ERANGE* = 34;	(* Math result not representable *)
+		EDEADLK* = 35;	(* Resource deadlock would occur *)
+		ENAMETOOLONG* = 36;	(* File name too long *)
+		ENOLCK* = 37;	(* No record locks available *)
+		ENOSYS* = 38;	(* Function not implemented *)
+		ENOTEMPTY* = 39;	(* Directory not empty *)
+		ELOOP* = 40;	(* Too many symbolic links encountered *)
+		EWOULDBLOCK* = EAGAIN;	(* Operation would block *)
+		ENOMSG* = 42;	(* No message of desired type *)
+		EIDRM* = 43;	(* Identifier removed *)
+		ECHRNG* = 44;	(* Channel number out of range *)
+		EL2NSYNC* = 45;	(* Level 2 not synchronized *)
+		EL3HLT* = 46;	(* Level 3 halted *)
+		EL3RST* = 47;	(* Level 3 reset *)
+		ELNRNG* = 48;	(* Link number out of range *)
+		EUNATCH* = 49;	(* Protocol driver not attached *)
+		ENOCSI* = 50;	(* No CSI structure available *)
+		EL2HLT* = 51;	(* Level 2 halted *)
+		EBADE* = 52;	(* Invalid exchange *)
+		EBADR* = 53;	(* Invalid request descriptor *)
+		EXFULL* = 54;	(* Exchange full *)
+		ENOANO* = 55;	(* No anode *)
+		EBADRQC* = 56;	(* Invalid request code *)
+		EBADSLT* = 57;	(* Invalid slot *)
+		EDEADLOCK* = EDEADLK;
+		EBFONT* = 59;	(* Bad font file format *)
+		ENOSTR* = 60;	(* Device not a stream *)
+		ENODATA* = 61;	(* No data available *)
+		ETIME* = 62;	(* Timer expired *)
+		ENOSR* = 63;	(* Out of streams resources *)
+		ENONET* = 64;	(* Machine is not on the network *)
+		ENOPKG* = 65;	(* Package not installed *)
+		EREMOTE* = 66;	(* Object is remote *)
+		ENOLINK* = 67;	(* Link has been severed *)
+		EADV* = 68;	(* Advertise error *)
+		ESRMNT* = 69;	(* Srmount error *)
+		ECOMM* = 70;	(* Communication error on send *)
+		EPROTO* = 71;	(* Protocol error *)
+		EMULTIHOP* = 72;	(* Multihop attempted *)
+		EDOTDOT* = 73;	(* RFS specific error *)
+		EBADMSG* = 74;	(* Not a data message *)
+		EOVERFLOW* = 75;	(* Value too large for defined data type *)
+		ENOTUNIQ* = 76;	(* Name not unique on network *)
+		EBADFD* = 77;	(* File descriptor in bad state *)
+		EREMCHG* = 78;	(* Remote address changed *)
+		ELIBACC* = 79;	(* Can not access a needed shared library *)
+		ELIBBAD* = 80;	(* Accessing a corrupted shared library *)
+		ELIBSCN* = 81;	(* .lib section in a.out corrupted *)
+		ELIBMAX* = 82;	(* Attempting to link in too many shared libraries *)
+		ELIBEXEC* = 83;	(* Cannot exec a shared library directly *)
+		EILSEQ* = 84;	(* Illegal byte sequence *)
+		ERESTART* = 85;	(* Interrupted system call should be restarted *)
+		ESTRPIPE* = 86;	(* Streams pipe error *)
+		EUSERS* = 87;	(* Too many users *)
+		ENOTSOCK* = 88;	(* Socket operation on non-socket *)
+		EDESTADDRREQ* = 89;	(* Destination address required *)
+		EMSGSIZE* = 90;	(* Message too long *)
+		EPROTOTYPE* = 91;	(* Protocol wrong type for socket *)
+		ENOPROTOOPT* = 92;	(* Protocol not available *)
+		EPROTONOSUPPORT* = 93;	(* Protocol not supported *)
+		ESOCKTNOSUPPORT* = 94;	(* Socket type not supported *)
+		EOPNOTSUPP* = 95;	(* Operation not supported on transport endpoint *)
+		EPFNOSUPPORT* = 96;	(* Protocol family not supported *)
+		EAFNOSUPPORT* = 97;	(* Address family not supported by protocol *)
+		EADDRINUSE* = 98;	(* Address already in use *)
+		EADDRNOTAVAIL* = 99;	(* Cannot assign requested address *)
+		ENETDOWN* = 100;	(* Network is down *)
+		ENETUNREACH* = 101;	(* Network is unreachable *)
+		ENETRESET* = 102;	(* Network dropped connection because of reset *)
+		ECONNABORTED* = 103;	(* Software caused connection abort *)
+		ECONNRESET* = 104;	(* Connection reset by peer *)
+		ENOBUFS* = 105;	(* No buffer space available *)
+		EISCONN* = 106;	(* Transport endpoint is already connected *)
+		ENOTCONN* = 107;	(* Transport endpoint is not connected *)
+		ESHUTDOWN* = 108;	(* Cannot send after transport endpoint shutdown *)
+		ETOOMANYREFS* = 109;	(* Too many references: cannot splice *)
+		ETIMEDOUT* = 110;	(* Connection timed out *)
+		ECONNREFUSED* = 111;	(* Connection refused *)
+		EHOSTDOWN* = 112;	(* Host is down *)
+		EHOSTUNREACH* = 113;	(* No route to host *)
+		EALREADY* = 114;	(* Operation already in progress *)
+		EINPROGRESS* = 115;	(* Operation now in progress *)
+		ESTALE* = 116;	(* Stale NFS file handle *)
+		EUCLEAN* = 117;	(* Structure needs cleaning *)
+		ENOTNAM* = 118;	(* Not a XENIX named type file *)
+		ENAVAIL* = 119;	(* No XENIX semaphores available *)
+		EISNAM* = 120;	(* Is a named type file *)
+		EREMOTEIO* = 121;	(* Remote I/O error *)
+		EDQUOT* = 122;	(* Quota exceeded *)
+		ENOMEDIUM* = 123;	(* No medium found *)
+		EMEDIUMTYPE* = 124;	(* Wrong medium type *)
+
+		PROT_NONE* = {};	(* No access *)
+		PROT_READ* = {2};	(* Pages can be read *)
+		PROT_WRITE* = {1};	(* Pages can be written *)
+		PROT_EXEC* = {0};	(* Pages can be executed *)
+		MAP_FILE* = {0};	(* Mapped from a file or device *)
+		MAP_ANON* = {1};	(* Allocated from anonymous virtual memory *)
+		MAP_COPY* = {5};	(* Virtual copy of region at mapping time *)
+		MAP_SHARED* = {4};	(* Share changes *)
+		MAP_PRIVATE* = {};	(* Changes private; copy pages on write *)
+		MAP_FIXED* = {8};	(* Map address must be exactly as requested *)
+		MAP_NOEXTEND* = {9} ;	(* For MAP_FILE, don't change file size *)
+		MAP_HASSEMPHORE*= {10};	(* Region may contain semaphores *)
+		MAP_INHERIT* = {11} ;	(* Region is retained after exec *)
+		MAP_FAILED* = -1;
+
+		O_RDONLY* = {} ;	(* Open read-only *)
+		O_WRONLY* = {0} ;	(* Open write-only *)
+		O_RDWR* = {1} ;	(* Open read/write *)
+
+	TYPE 
+		__ftw_func_t* = PROCEDURE (fileName: PtrSTR; VAR [nil] stat: stat_t; flag: INTEGER): INTEGER;
+		PtrVoid* = INTEGER;
+		PtrSTR* = POINTER TO ARRAY [untagged] OF SHORTCHAR;
+		PtrWSTR* = POINTER TO ARRAY [untagged] OF CHAR;
+		PtrInt* = INTEGER;
+		StrArray* = POINTER TO ARRAY [untagged] OF PtrSTR;
+		PtrFILE* = INTEGER;
+		PtrDIR* = INTEGER;
+		PtrProc* = INTEGER;
+		clock_t* = INTEGER;
+		jmp_buf* = ARRAY [untagged] 6 OF INTEGER; (* bx, si, di, bp, sp, pc *)
+		mode_t* = SET;
+		off_t* = INTEGER;
+		SelectorFunc* = PROCEDURE (dirent: Dirent): INTEGER;
+		CmpFunc* = PROCEDURE (VAR [nil] dirent1, dirent2: PtrDirent): INTEGER;
+		size_t* = INTEGER; (* should be unsigned int *)
+		sigjmp_buf* = RECORD [untagged] 
+			buf*: jmp_buf;
+			mask_was_saved*: INTEGER;
+			saved_mask*: sigset_t;
+		END; 
+		
+		PtrDirent* = POINTER TO Dirent;
+		PtrDirentArray* = POINTER TO ARRAY [untagged] OF Dirent;
+		Dirent* = RECORD  [untagged]
+			d_ino*: INTEGER;	(* inode number *)
+			d_off*: off_t;	(* offset to this dirent *)
+			d_reclen*: SHORTINT;	(* length of this d_name *)
+			d_type*: BYTE;
+			d_name*: ARRAY[untagged]  NAME_MAX+1 OF SHORTCHAR;		(* file name (null-terminated) *)
+		END;
+		
+		pid_t* = INTEGER;
+		uid_t* = INTEGER;
+		sigval_t* = INTEGER;
+
+		siginfo_t* = RECORD [untagged]
+			si_signo*: INTEGER; 	(* Signal number *)
+			si_errno*: INTEGER;  	(* An errno value *)
+			si_code*: INTEGER;   	(* Signal code *)
+			si_pid*: pid_t;    	(* Sending process ID *)
+			si_uid*: uid_t;    	(* Real user ID of sending process *)
+			si_status*: INTEGER; 	(* Exit value or signal *)
+			si_utime*: clock_t;  	(* User time consumed *)
+			si_stime*: clock_t;  	(* System time consumed *)
+			si_value*: sigval_t;  	(* Signal value *)
+			si_int*: INTEGER;    	(* POSIX.1b signal *)
+			si_ptr*: PtrVoid;    	(* POSIX.1b signal *)
+			si_addr*: PtrVoid;   	(* Memory location which caused fault *)
+			si_band*: INTEGER;   	(* Band event *)
+			si_fd*: INTEGER;     	(* File descriptor *)
+		END;
+		Ptrsiginfo_t* = POINTER TO siginfo_t;
+		
+		sigset_t* = ARRAY [untagged] 128 OF BYTE;
+		Ptrsigset_t* = INTEGER;
+		sigaction_t* = RECORD [untagged]
+			sa_sigaction*: PROCEDURE (sig: INTEGER; siginfo: Ptrsiginfo_t; ptr: Ptrucontext_t); (* union with sa_handler*: PtrProc;*)
+			sa_mask*: sigset_t;
+			sa_flags*: SET;
+			sa_restorer*: LONGINT;
+		END;
+		
+		stack_t* = RECORD [untagged]
+			ss_sp*: PtrVoid;    
+			ss_flags*: INTEGER;    
+			ss_size*: size_t;
+		END;
+		
+		stat_t* = RECORD [untagged]
+			st_dev*: LONGINT;	(* device *)
+			__pad1: SHORTINT;
+			st_ino*: INTEGER;	(* 64? inode *)
+			st_mode*: mode_t;	(* protection *)
+			st_nlink*: INTEGER; 	(* number of hard links *)
+			st_uid*: uid_t;	(* user ID of owner *)
+			st_gid*: INTEGER;	(* group ID of owner *)
+			st_rdev*: LONGINT;	(* device type (if inode device) *)
+			__pad2: SHORTINT;
+			st_size*: off_t;	(* 64? total size, in bytes *)
+			st_blksize*: INTEGER;	(* blocksize for filesystem I/O *)
+			st_blocks*: INTEGER;	(* 64? number of blocks allocated *)
+			st_atime*: INTEGER;	(* time of last access *)
+			__unused1:  INTEGER;
+			st_mtime*: INTEGER;	(* time of last modification *) 
+			__unused2:  INTEGER;
+			st_ctime*: INTEGER;	(* time of last change *)
+			__unused3:  INTEGER;
+			__unused4:  INTEGER;
+			__unused5:  INTEGER;
+		END;
+		
+		fpreg* = RECORD [untagged]
+			significand*: ARRAY [untagged] 4 OF CHAR;
+			exponent*: CHAR;
+		END;
+
+		fpstate* = RECORD [untagged]
+			cw*: INTEGER; 	(* unsigned long int *)
+			sw*: INTEGER; 	(* unsigned long int *)
+			tag*: INTEGER; 	(* unsigned long int *)
+			ipoff*: INTEGER; 	(* unsigned long int *)
+			cssel*: INTEGER; 	(* unsigned long int *)
+			dataoff*: INTEGER; 	(* unsigned long int *)
+			datasel*: INTEGER; 	(* unsigned long int *)
+			_st: ARRAY [untagged] 8 OF fpreg;
+			status*: INTEGER; 	(* unsigned long int *)
+		END;
+
+		gregset_t* = ARRAY [untagged] 19 OF INTEGER;
+		fpregset_t* = POINTER TO fpstate;
+		
+		mcontext_t*  = RECORD [untagged]
+			gregs*: gregset_t;
+			fpregs*: fpregset_t;
+			oldmask*: INTEGER;	(* unsigned long int *)
+			cr2*: INTEGER; 	(* unsigned long int *)
+		END;
+		
+		Ptrucontext_t* = POINTER TO ucontext_t;
+		ucontext_t* = RECORD [untagged]
+			uc_flags*: INTEGER;	(* unsigned long int *)
+			uc_link*: Ptrucontext_t;
+			uc_stack*: stack_t;
+			uc_mcontext*: mcontext_t;
+			uc_sigmask: sigset_t;
+			__fpregs_mem*: fpstate;
+		END;
+		
+		(* Times and Dates *)
+		
+		tm* = POINTER TO tmDesc;
+		tmDesc* = RECORD [untagged]
+			tm_sec*: INTEGER;	(* seconds *)
+			tm_min*: INTEGER;	(* minutes *)
+			tm_hour*: INTEGER;	(* hours *)
+			tm_mday*: INTEGER;	(* day of the month *)
+			tm_mon*: INTEGER;	(* month *)
+			tm_year*: INTEGER;	(* year *)
+			tm_wday*: INTEGER;	(* day of the week *)
+			tm_yday*: INTEGER;	(* day in the year *)
+			tm_isdst*: INTEGER;	(* daylight saving time *)
+		END;
+		time_t* = INTEGER;
+
+	VAR
+		timezone*: INTEGER; (* seconds from GMT *)		
+		stdin*, stdout*, stderr* : PtrFILE; 
+
+	PROCEDURE [ccall] calloc* (num, size: size_t): PtrVoid;
+	PROCEDURE [ccall] clock* (): clock_t;
+	PROCEDURE [ccall] closedir* (dir: PtrDIR): INTEGER;
+	PROCEDURE [ccall] chmod* (path: PtrSTR; mode: mode_t);
+	PROCEDURE [ccall] exit* (status: INTEGER);
+	PROCEDURE [ccall] fclose* (fp: PtrFILE): INTEGER;
+	PROCEDURE [ccall] fflush* (fp: PtrFILE): INTEGER;
+	PROCEDURE [ccall] fopen* (filename, mode: PtrSTR): PtrFILE;
+	PROCEDURE [ccall] feof* (fp: PtrFILE): INTEGER;
+	PROCEDURE [ccall] fread* (ptr: PtrVoid; size, nobj: size_t; stream: PtrFILE): size_t;
+	PROCEDURE [ccall] fseek* (stream: PtrFILE; offset, origin: INTEGER): INTEGER;
+	PROCEDURE [ccall] free* (p: PtrVoid);
+	PROCEDURE [ccall] ftell* (stream: PtrFILE): LONGINT;
+	PROCEDURE [ccall] ftw* (filename: PtrSTR; func: __ftw_func_t; descriptors: INTEGER): INTEGER;
+	PROCEDURE [ccall] fwrite* (ptr: PtrVoid; size, nobj: size_t; stream: PtrFILE): size_t;
+	PROCEDURE [ccall] getcwd* (buf: PtrSTR; size: size_t): PtrSTR;
+	PROCEDURE [ccall] getcontext* (ucontext_t: Ptrucontext_t): INTEGER;
+	PROCEDURE [ccall] gets* (s: PtrSTR);
+	PROCEDURE [ccall] fgets* (s: PtrSTR; n: INTEGER; fp: PtrFILE): PtrSTR;
+	PROCEDURE [ccall] gmtime* (VAR timep: time_t): tm;
+	PROCEDURE [ccall] kill* (pid: pid_t; sig: INTEGER): INTEGER;
+	PROCEDURE [ccall] localtime* (VAR timep: time_t): tm;
+	PROCEDURE [ccall] malloc* (size: size_t): PtrVoid;
+	PROCEDURE [ccall] mkdir* (pathname: PtrSTR; mode: mode_t): INTEGER;
+	PROCEDURE [ccall] mktime* (timeptr: tm): time_t;
+	PROCEDURE [ccall] opendir* (name: PtrSTR): PtrDIR;
+	PROCEDURE [ccall] printf* (s: PtrSTR): INTEGER;	
+	PROCEDURE [ccall] readdir* (dir: PtrDIR): PtrDirent;
+	PROCEDURE [ccall] remove* (filename: PtrSTR): INTEGER;
+	PROCEDURE [ccall] rename* (oldname, newname: PtrSTR): INTEGER;
+	PROCEDURE [ccall] scandir* (dir: PtrDIR; namelist: PtrDirentArray; selector: SelectorFunc; cmp: CmpFunc): INTEGER;
+	PROCEDURE [ccall] setcontext* (ucontext_t: Ptrucontext_t): INTEGER;
+	PROCEDURE [ccall] setjmp* (VAR env: jmp_buf): INTEGER;
+	PROCEDURE [ccall] sigaction* (sig_num: INTEGER; VAR [nil] act: sigaction_t; VAR [nil] oldact: sigaction_t): INTEGER;
+	PROCEDURE [ccall] sigaddset* (set: Ptrsigset_t; sig: INTEGER): INTEGER;
+	PROCEDURE [ccall] sigdelset* (set: Ptrsigset_t; sig: INTEGER): INTEGER;
+	PROCEDURE [ccall] sigemptyset* (set: Ptrsigset_t): INTEGER;
+	PROCEDURE [ccall] sigfillset* (set: Ptrsigset_t): INTEGER;
+	PROCEDURE [ccall] sigismemeber* (set: Ptrsigset_t; sig: INTEGER): INTEGER;
+	PROCEDURE [ccall] siglongjmp* (VAR env: sigjmp_buf; val: INTEGER);
+	PROCEDURE [ccall] signal* (sig_num: INTEGER; sighandler: PtrProc): PtrProc;
+	PROCEDURE [ccall] sigsetjmp* ["__sigsetjmp"] (VAR env: sigjmp_buf; savemask: INTEGER): INTEGER; 
+(*
+	PROCEDURE [ccall] stat* (filename: PtrSTR; VAR buf: stat_t): INTEGER;   stat is a macro and expands to __xstat(3, filename, buf)
+*)
+	PROCEDURE [ccall] __xstat* (version: INTEGER; filename: PtrSTR; VAR buf: stat_t): INTEGER;
+	PROCEDURE [ccall] strftime* (s: PtrSTR; max: size_t; format: PtrSTR; ptm: tm): size_t;
+	PROCEDURE [ccall] time* (VAR [nil] t: time_t): time_t;
+
+	PROCEDURE [ccall] __errno_location*(): INTEGER;
+
+	PROCEDURE [ccall] open* (name: PtrSTR; flags: SET; mode: mode_t): INTEGER;
+	PROCEDURE [ccall] close* (d: INTEGER): INTEGER;
+	PROCEDURE [ccall] read* (d: INTEGER; buf: PtrVoid; nbytes: size_t): INTEGER;
+	PROCEDURE [ccall] write* (d: INTEGER; buf: PtrVoid; nBytes: size_t): INTEGER;
+
+	PROCEDURE [ccall] mmap* (addr: PtrVoid; len: size_t; prot: SET; flags: SET; fd, offset: off_t): PtrVoid;
+	PROCEDURE [ccall] munmap* (addr: PtrVoid; len: size_t): INTEGER;
+	PROCEDURE [ccall] mprotect* (addr: PtrVoid; len: size_t; prot: SET): INTEGER;
+
+	PROCEDURE [ccall] getenv* (name: PtrSTR): PtrSTR;
+
+END LinLibc.

BIN
BlackBox/Linux/Lin/Mod/linHostFiles.odc


+ 1304 - 0
BlackBox/Linux/Lin/Mod/linHostFiles.txt

@@ -0,0 +1,1304 @@
+MODULE HostFiles;
+
+	(* THIS IS TEXT COPY OF linHostFiles.odc *)
+	(* DO NOT EDIT *)
+
+	IMPORT SYSTEM, Kernel, Files, LinLibc;
+
+	CONST
+		tempName = "odcxxxxx";
+		docType = "odc";
+		
+		serverVersion = TRUE;
+
+		pathLen* = 260;
+
+		nofbufs = 4;	(* max number of buffers per file *)
+		bufsize = 2 * 1024;	(* size of each buffer *)
+
+		invalid = LinLibc.NULL;
+		
+		temp = 0; new = 1; shared = 2; hidden = 3; exclusive = 4; closed = 5;	(* file states *)
+		create = -1;
+		
+		ok = 0;
+		invalidName = 1;
+		invalidNameErr = MAX(INTEGER); (* On Windows this is 123 *)
+		notFound = 2;
+		fileNotFoundErr = LinLibc.ENOENT;
+		pathNotFoundErr = LinLibc.ENOENT;
+		existsAlready = 3;
+		fileExistsErr = LinLibc.EEXIST;
+		alreadyExistsErr = LinLibc.EEXIST; (* is alreadyExistsErr needed? *)
+		writeProtected = 4;
+		writeProtectedErr = LinLibc.EACCES;
+		ioError = 5; (* same as LinLibc.EIO *)
+		accessDenied = 6;
+		accessDeniedErr = LinLibc.EACCES;
+		sharingErr = LinLibc.EACCES;
+		netAccessDeniedErr = LinLibc.EACCES;
+		notEnoughMem = 80;
+		notEnoughMemoryErr = LinLibc.ENOMEM;
+		notEnoughDisk = 81;
+		diskFullErr = LinLibc.EDQUOT;
+		tooManyOpenFilesErr = LinLibc.EMFILE;
+		
+		noMoreFilesErr = 18;
+		
+		cancel = -8; retry = -9;
+
+	TYPE
+		FullName* = ARRAY pathLen OF CHAR;
+
+		Locator* = POINTER TO RECORD (Files.Locator)
+			path-: FullName;	(* without trailing "/" *)
+			maxLen-: INTEGER;	(* maximum name length *)
+			caseSens-: BOOLEAN;	(* case sensitive file compares *)
+			rootLen-: INTEGER	(* for network version *)
+		END;
+
+		Buffer = POINTER TO RECORD
+			dirty: BOOLEAN;
+			org, len: INTEGER;
+			data: ARRAY bufsize OF BYTE
+		END;
+
+		File = POINTER TO RECORD (Files.File)
+			state: INTEGER;
+			name: FullName;
+			ref: LinLibc.PtrFILE;
+			loc: Locator;
+			swapper: INTEGER;	(* index into file table / next buffer to swap *)
+			len: INTEGER;
+			bufs: ARRAY nofbufs OF Buffer;
+			t: LONGINT	(* time stamp of last file operation *)
+		END;
+
+		Reader = POINTER TO RECORD (Files.Reader)
+			base: File;
+			org, offset: INTEGER;
+			buf: Buffer
+		END;
+
+		Writer = POINTER TO RECORD (Files.Writer)
+			base: File;
+			org, offset: INTEGER;
+			buf: Buffer
+		END;
+
+		Directory = POINTER TO RECORD (Files.Directory)
+			temp, startup: Locator
+		END;
+
+		Identifier = RECORD (Kernel.Identifier)
+			name: FullName
+		END;
+		
+		Searcher = RECORD (Kernel.Identifier)
+			t0: INTEGER;
+			f: File
+		END;
+		
+		Counter = RECORD (Kernel.Identifier)
+			count: INTEGER
+		END;
+		
+		ShortName = ARRAY pathLen OF SHORTCHAR;
+		
+	VAR
+		MapParamString*: PROCEDURE(in, p0, p1, p2: ARRAY OF CHAR; OUT out: ARRAY OF CHAR);
+		appName-: FullName;
+		dir: Directory;
+		wildcard: Files.Type;
+		startupDir: FullName;
+		startupLen: INTEGER;
+		res: INTEGER;
+		
+	(* debugging functions *)
+
+	PROCEDURE Msg (IN str: ARRAY OF CHAR);
+		VAR ss: ARRAY 1024 OF SHORTCHAR; res, l: INTEGER;
+	BEGIN
+		ss := SHORT(str);
+		l := LEN(ss$);
+		ss[l] := 0AX; ss[l + 1] := 0X;
+		res := LinLibc.printf(ss);
+		res := LinLibc.fflush(0)
+	END Msg;
+	
+	PROCEDURE Int (x: LONGINT);
+		VAR j, k: INTEGER; ch: CHAR; a, s: ARRAY 32 OF CHAR;
+	BEGIN
+		IF x # MIN(LONGINT) THEN
+			IF x < 0 THEN s[0] := "-"; k := 1; x := -x ELSE k := 0 END;
+			j := 0; REPEAT a[j] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(j) UNTIL x = 0
+		ELSE
+			a := "8085774586302733229"; s[0] := "-"; k := 1;
+			j := 0; WHILE a[j] # 0X DO INC(j) END
+		END;
+		ASSERT(k + j < LEN(s), 20);
+		REPEAT DEC(j); ch := a[j]; s[k] := ch; INC(k) UNTIL j = 0;
+		s[k] := 0X;
+		Msg(s);
+	END Int;
+	
+	(* end of debugging functions *)
+	
+	(*	get error num from linux	*)
+	PROCEDURE LinLibc_errno (): INTEGER;
+		VAR
+			addr, errno: INTEGER;
+	BEGIN
+		addr := LinLibc.__errno_location();
+		SYSTEM.GET(addr, errno);
+		RETURN errno
+	END LinLibc_errno;
+	
+	PROCEDURE Error (n: INTEGER): INTEGER;
+		VAR res: INTEGER;
+	BEGIN
+		IF n = ok THEN res := ok
+		ELSIF n = invalidNameErr THEN res := invalidName
+		ELSIF (n = fileNotFoundErr) OR (n = pathNotFoundErr) THEN res := notFound
+		ELSIF (n = fileExistsErr) OR (n = alreadyExistsErr) THEN res := existsAlready
+		ELSIF n = writeProtectedErr THEN res := writeProtected
+		ELSIF (n = sharingErr) OR (n = accessDeniedErr) OR (n = netAccessDeniedErr) THEN res := accessDenied
+		ELSIF n = notEnoughMemoryErr THEN res := notEnoughMem
+		ELSIF (n = diskFullErr) OR (n = tooManyOpenFilesErr) THEN res := notEnoughDisk
+		ELSE res := -n
+		END;
+		RETURN res
+	END Error;
+
+	PROCEDURE Diff (VAR a, b: ARRAY OF CHAR; caseSens: BOOLEAN): INTEGER;
+		VAR i: INTEGER; cha, chb: CHAR;
+	BEGIN
+		i := 0;
+		REPEAT
+			cha := a[i]; chb := b[i]; INC(i);
+			IF cha # chb THEN
+				IF ~caseSens THEN
+					IF (cha >= "a") & ((cha <= "z") OR (cha >= 0E0X) & (cha <= 0FEX) & (cha # 0F7X)) THEN
+						cha := CAP(cha)
+					END;
+					IF (chb >= "a") & ((chb <= "z") OR (chb >= 0E0X) & (chb <= 0FEX) & (chb # 0F7X)) THEN
+						chb := CAP(chb)
+					END
+				END;
+				IF cha = "\" THEN cha := "/" END;
+				IF chb = "\" THEN chb := "/" END;
+				IF cha # chb THEN RETURN ORD(cha) - ORD(chb) END
+			END
+		UNTIL cha = 0X;
+		RETURN 0
+	END Diff;
+	
+	PROCEDURE Stat (IN fname: FullName; VAR buf: LinLibc.stat_t; OUT res: INTEGER);
+		VAR s: ShortName;
+	BEGIN
+		s := SHORT(fname);
+		res := LinLibc.__xstat(3, s, buf); (* macro expansion of "stat" *)
+	END Stat;
+	
+	PROCEDURE ModeToAttr (mode: SET; OUT attr: SET; OUT isDir: BOOLEAN);
+		CONST read = 8; write = 7; execute = 6; file = 15; (* bits for permissions for the current user (see man chmod) *)
+	BEGIN
+		attr := {};
+		IF ~(write IN mode) THEN INCL(attr, Files.readOnly) END;
+		isDir := ~(file IN mode) (* see "man 2 stat" for details *)
+	END ModeToAttr;	
+							
+	PROCEDURE NewLocator* (IN fname: ARRAY OF CHAR): Locator;
+		VAR loc: Locator; i: INTEGER;
+	BEGIN
+		NEW(loc); loc.path := fname$; i := 0;
+		WHILE loc.path[i] # 0X DO INC(i) END;
+		IF (loc.path[i-1] = "/") OR (loc.path[i-1] = "\") THEN loc.path[i-1] := 0X END;
+		loc.maxLen := LinLibc.NAME_MAX; loc.caseSens := TRUE;
+		RETURN loc
+	END NewLocator;
+	
+	PROCEDURE GetType (IN name: ARRAY OF CHAR; VAR type: Files.Type);
+		VAR i, j: INTEGER; ch: CHAR;
+	BEGIN
+		i := 0; j := 0;
+		WHILE name[i] # 0X DO INC(i) END;
+		WHILE (i > 0) & (name[i] # ".") DO DEC(i) END;
+		IF i > 0 THEN
+			INC(i); ch := name[i];
+			WHILE (j < LEN(type) - 1) & (ch # 0X) DO
+				IF (ch >= "A") & (ch <= "Z") THEN ch := CHR(ORD(ch) + (ORD("a") - ORD("A"))) END;
+				type[j] := ch; INC(j);
+				INC(i); ch := name[i]
+			END
+		END;
+		type[j] := 0X
+	END GetType;
+
+	PROCEDURE Append (IN path, name: ARRAY OF CHAR; type: Files.Type; max: INTEGER;
+		VAR res: ARRAY OF CHAR
+	);
+		VAR i, j, n, m, dot: INTEGER; ch: CHAR;
+	BEGIN
+		i := 0;
+		WHILE path[i] # 0X DO res[i] := path[i]; INC(i) END;
+		IF path # "" THEN
+			ASSERT((res[i-1] # "/") & (res[i-1] # "\"), 100);
+			res[i] := "/"; INC(i)
+		END;
+		j := 0; ch := name[0]; n := 0; m := max; dot := -1;
+		IF max = 12 THEN m := 8 END;
+		WHILE (i < LEN(res) - 1) & (ch # 0X) DO
+			IF (ch = "/") OR (ch = "\") THEN
+				res[i] := ch; INC(i); n := 0; m := max; dot := -1;
+				IF max = 12 THEN m := 8 END
+			ELSIF (n < m) OR (ch = ".") & (n = 8) THEN
+				res[i] := ch; INC(i); INC(n);
+				IF ch = "." THEN dot := n;
+					IF max = 12 THEN m := n + 3 END
+				END
+			END;
+			INC(j); ch := name[j]
+		END;
+		IF (dot = -1) & (type # "") THEN
+			IF max = 12 THEN m := n + 4 END;
+			IF (n < m) & (i < LEN(res) - 1) THEN res[i] := "."; INC(i); INC(n); dot := n END
+		END;
+		IF n = dot THEN j := 0;
+			WHILE (n < m) & (i < LEN(res) - 1) & (type[j] # 0X) DO res[i] := type[j]; INC(i); INC(j) END
+		END;
+		res[i] := 0X
+	END Append;
+	
+	PROCEDURE CloseFileHandle (f: File; VAR res: INTEGER);
+	BEGIN
+		IF (f.ref = invalid) OR (LinLibc.fclose(f.ref) = 0) THEN res := ok	(* !!! *)
+		ELSE res := LinLibc_errno()
+		END;
+		f.ref := invalid
+	END CloseFileHandle;
+
+	PROCEDURE CloseFile (f: File; VAR res: INTEGER);
+		VAR s: INTEGER; n: ShortName;
+	BEGIN
+		IF f.state = exclusive THEN 
+			f.Flush;
+			res := LinLibc.fflush(f.ref)
+		 END;
+		s := f.state; f.state := closed;
+		CloseFileHandle (f, res);
+		IF (s IN {temp, new, hidden}) & (f.name # "") THEN
+			n := SHORT(f.name$);
+			res := LinLibc.remove(n)
+		END
+	END CloseFile;
+
+	PROCEDURE (f: File) FINALIZE;
+		VAR res: INTEGER;
+	BEGIN
+		IF f.state # closed THEN CloseFile(f, res) END
+	END FINALIZE;
+	
+	PROCEDURE (VAR id: Identifier) Identified (): BOOLEAN;
+		VAR f: File;
+	BEGIN
+		f := id.obj(File);
+		RETURN (f.state IN {shared, exclusive}) & (Diff(f.name, id.name, f.loc.caseSens) = 0)
+	END Identified;
+
+	PROCEDURE ThisFile (VAR name: FullName): File;
+		VAR id: Identifier; p: ANYPTR;
+	BEGIN
+		id.typ := SYSTEM.TYP(File); id.name := name$;
+		p := Kernel.ThisFinObj(id);
+		IF p # NIL THEN RETURN p(File)
+		ELSE RETURN NIL
+		END
+	END ThisFile;
+
+	PROCEDURE (VAR s: Searcher) Identified (): BOOLEAN;
+		VAR f: File;
+	BEGIN
+		f := s.obj(File);
+		IF (f.ref # invalid) & ((s.f = NIL) OR (f.t < s.f.t)) THEN s.f := f END;
+		RETURN FALSE
+	END Identified;
+	
+	PROCEDURE SearchFileToClose;
+		VAR s: Searcher; p: ANYPTR; (* res: LONGINT; *)
+	BEGIN
+		s.typ := SYSTEM.TYP(File); s.f := NIL;
+		p := Kernel.ThisFinObj(s);
+		IF s.f # NIL THEN
+			res := LinLibc.fclose(s.f.ref); s.f.ref := invalid;
+			IF res = 0 THEN res := LinLibc_errno(); HALT(100) END
+		END
+	END SearchFileToClose;
+	
+	PROCEDURE ExistingFile (VAR n: ShortName): BOOLEAN;
+		VAR f: LinLibc.PtrFILE; ret: BOOLEAN; res: INTEGER;
+	BEGIN
+		f := LinLibc.fopen(n, "r");
+		IF f  # LinLibc.NULL THEN
+			res := LinLibc.fclose(f); 
+			ret := TRUE
+		ELSE
+			ret := FALSE
+		END;
+		RETURN ret
+	END ExistingFile;
+	
+	PROCEDURE MoveFile (VAR old, new: ShortName; VAR res: INTEGER); (* as the WinApi.MoveFile *)
+	BEGIN
+		IF ExistingFile(new) THEN
+			res := fileExistsErr
+		ELSE
+			IF LinLibc.rename(old, new) = 0 THEN res := ok
+			ELSE res := LinLibc_errno();
+			END
+		END
+	END MoveFile;
+	
+	PROCEDURE NewFileRef (state: INTEGER; VAR name: FullName; VAR ref, res: INTEGER);
+		VAR n: ShortName;
+	BEGIN
+		n := SHORT(name$);
+		IF state = create THEN (* Create should fail if file already exists *)
+			IF ExistingFile(n) THEN
+				ref := invalid; res := fileExistsErr
+			ELSE
+				ref := LinLibc.fopen(n, "w+");
+				IF ref = invalid THEN res := LinLibc_errno() ELSE res := ok END
+			END
+		ELSIF state = shared THEN
+			ref := LinLibc.fopen(n, "r");
+			IF ref = invalid THEN res := LinLibc_errno() ELSE res := ok END
+		ELSE
+			ref := LinLibc.fopen(n, "r+");
+			IF ref = invalid THEN res := LinLibc_errno() ELSE res := ok END
+		END
+	END NewFileRef;
+	
+	PROCEDURE OpenFile (state: INTEGER; VAR name: FullName; VAR ref, res: INTEGER);
+	BEGIN
+		NewFileRef(state, name, ref, res);
+		IF ref = invalid THEN
+			IF res = tooManyOpenFilesErr THEN
+				Kernel.Collect;
+				NewFileRef(state, name, ref, res);
+				IF ref = invalid THEN
+					res := LinLibc_errno();
+					IF res = tooManyOpenFilesErr THEN
+						SearchFileToClose;
+						NewFileRef(state, name, ref, res);
+					END
+				ELSE res := ok
+				END
+			END
+		ELSE res := ok
+		END
+	END OpenFile;
+	
+	PROCEDURE GetTempFileName (VAR path, name: FullName; num: INTEGER);
+		VAR i: INTEGER; str: ARRAY 16 OF CHAR;
+	BEGIN
+		str := tempName; i := 7;
+		WHILE i > 2 DO
+			str[i] := CHR(num MOD 10 + ORD("0")); DEC(i); num := num DIV 10
+		END;
+		Append(path, str, "", 8, name)
+	END GetTempFileName;
+	
+	PROCEDURE CreateFile (f: File; VAR res: INTEGER);
+		VAR num, n: INTEGER;
+	BEGIN
+		IF f.name = "" THEN
+			num := LinLibc.clock(); n := 200;
+			REPEAT
+				GetTempFileName(f.loc.path, f.name, num); INC(num); DEC(n);
+				OpenFile(create, f.name, f.ref, res)
+			UNTIL (res # fileExistsErr) OR (n = 0)
+		ELSE
+			OpenFile(f.state, f.name, f.ref, res)
+		END
+	END CreateFile;
+
+	PROCEDURE Delete (VAR fname, path: FullName; VAR res: INTEGER); 
+		VAR num, n: INTEGER; f: File; new: FullName; attr: SET; fn, nn: ShortName; buf: LinLibc.stat_t; isDir: BOOLEAN;
+	BEGIN
+		ASSERT(fname # "", 100);
+		f := ThisFile(fname); fn := SHORT(fname$);
+		IF f = NIL THEN
+			IF LinLibc.remove(fn) = 0 THEN 
+				res := ok
+			ELSE 
+				res := LinLibc.fflush(0);
+				IF LinLibc.remove(fn) = 0 THEN res := ok ELSE res := LinLibc_errno() END
+			END
+		ELSE (* still in use => make it anonymous *)
+			IF f.ref # invalid THEN res := LinLibc.fclose(f.ref); f.ref := invalid END;	(* !!! *)
+			Stat(f.name, buf, res);
+			ModeToAttr(buf.st_mode, attr, isDir);
+			IF (res = ok) & ~(Files.readOnly IN attr) THEN
+				num := LinLibc.clock(); n := 200;
+				REPEAT
+					GetTempFileName(path, new, num); INC(num); DEC(n);
+					nn := SHORT(new$);
+					MoveFile(fn, nn, res);
+				UNTIL (res # fileExistsErr) OR (n = 0);
+				IF res = ok THEN
+					f.state := hidden; f.name := new$
+				END
+			ELSE
+				res := writeProtectedErr
+			END
+		END
+	END Delete;
+
+	PROCEDURE FlushBuffer (f: File; i: INTEGER);
+		VAR buf: Buffer; res: INTEGER;
+	BEGIN
+		buf := f.bufs[i];
+		IF (buf # NIL) & buf.dirty THEN
+			IF f.ref = invalid THEN CreateFile(f, res) (* ASSERT(res = ok, 100) *) END;
+			IF f.ref # invalid THEN
+				res := LinLibc.fseek(f.ref, buf.org, LinLibc.SEEK_SET);
+				IF LinLibc.fwrite(SYSTEM.ADR(buf.data), 1, buf.len, f.ref) < buf.len THEN
+					res := LinLibc_errno(); HALT(101)
+				END;
+				res := LinLibc.fflush(f.ref);
+				buf.dirty := FALSE; f.t := Kernel.Time()
+			END
+		END
+	END FlushBuffer;
+
+	(* File *)
+
+	PROCEDURE (f: File) NewReader (old: Files.Reader): Files.Reader;
+		VAR r: Reader;
+	BEGIN	(* portable *)
+		ASSERT(f.state # closed, 20);
+		IF (old # NIL) & (old IS Reader) THEN r := old(Reader) ELSE NEW(r) END;
+		IF r.base # f THEN
+			r.base := f; r.buf := NIL; r.SetPos(0)
+		END;
+		r.eof := FALSE;
+		RETURN r
+	END NewReader;
+
+	PROCEDURE (f: File) NewWriter (old: Files.Writer): Files.Writer;
+		VAR w: Writer;
+	BEGIN	(* portable *)
+		ASSERT(f.state # closed, 20);
+		IF (old # NIL) & (old IS Writer) THEN w := old(Writer) ELSE NEW(w) END;
+		IF w.base # f THEN
+			w.base := f; w.buf := NIL; w.SetPos(f.len)
+		END;
+		RETURN w
+	END NewWriter;
+
+	PROCEDURE (f: File) Length (): INTEGER;
+	BEGIN	(* portable *)
+		RETURN f.len
+	END Length;
+	
+	PROCEDURE (f: File) Flush;
+		VAR i: INTEGER;
+	BEGIN	(* portable *)
+		i := 0; WHILE i # nofbufs DO FlushBuffer(f, i); INC(i) END
+	END Flush;
+	
+	PROCEDURE GetPath (VAR fname, path: FullName);
+		VAR i: INTEGER;
+	BEGIN
+		path := fname$; i := 0;
+		WHILE path[i] # 0X DO INC(i) END;
+		WHILE (i > 0) & (path[i] # "\") & (path[i] # "/") & (path[i-1] # ":") DO DEC(i) END;
+		path[i] := 0X
+	END GetPath;
+	
+	PROCEDURE CreateDir (VAR path: FullName; VAR res: INTEGER);
+		VAR (*sec: KERNEL32.SecurityAttributes;*) p: FullName; s: ShortName;
+	BEGIN
+		ASSERT(path # "", 100);
+		s := SHORT(path$);
+		res := LinLibc.mkdir(s, {0..MAX(SET)}); (* full rights are masked with the umask, is this correct? *)
+		IF res # ok THEN
+			res := LinLibc_errno();
+			IF (res = LinLibc.ENOTDIR) OR (res = LinLibc.ENOENT) THEN
+				GetPath(path, p);
+				CreateDir(p, res);	(* recursive call *)
+				IF res = ok THEN
+					res := LinLibc.mkdir(s, {0..MAX(SET)}); (* full rights are masked with the umask, is this correct? *)
+					IF res # ok THEN res := LinLibc_errno() END
+				END
+			END
+		END
+	END CreateDir;
+	
+	PROCEDURE CheckPath (VAR path: FullName; ask: BOOLEAN; VAR res: INTEGER);
+		VAR s: ARRAY 300 OF CHAR; t: ARRAY 32 OF CHAR; 
+	BEGIN
+		(*IF ask THEN
+			IF MapParamString # NIL THEN
+				MapParamString("#Host:CreateDir", path, "", "", s);
+				MapParamString("#Host:MissingDirectory", "", "", "", t)
+			ELSE
+				s := path$; t := "Missing Directory"
+			END;
+			res := Kernel.MessageBox(t, s, {Kernel.mbOk, Kernel.mbCancel})
+		ELSE
+			res := Kernel.mbOk
+		END;*)
+		(*IF res = Kernel.mbOk THEN*) CreateDir(path, res)
+		(*ELSIF res = Kernel.mbCancel THEN res := cancel
+		END*)
+	END CheckPath;
+
+	PROCEDURE CheckDelete (VAR fname, path: FullName; ask: BOOLEAN; VAR res: INTEGER);
+		VAR s: ARRAY 300 OF CHAR; t: ARRAY 16 OF CHAR; 
+	BEGIN
+		REPEAT
+			Delete(fname, path, res);
+			IF (res = writeProtectedErr)
+				OR (res = sharingErr)
+				OR (res = accessDeniedErr)
+				OR (res = netAccessDeniedErr)
+			THEN
+				(*IF ask THEN
+					IF MapParamString # NIL THEN
+						IF res = writeProtectedErr THEN
+							MapParamString("#Host:ReplaceWriteProtected", fname, 0DX, "", s)
+						ELSIF (res = accessDeniedErr) OR (res = netAccessDeniedErr) THEN
+							MapParamString("#Host:ReplaceAccessDenied", fname, 0DX, "", s)
+						ELSE
+							MapParamString("#Host:ReplaceInUse", fname, 0DX, "", s)
+						END;
+						MapParamString("#Host:FileError", "", "", "", t)
+					ELSE
+						s := fname$; t := "File Error"
+					END;
+					res := Kernel.MessageBox(t, s, {Kernel.mbRetry, Kernel.mbCancel});
+					IF res = Kernel.mbCancel THEN res := cancel
+					ELSIF res = Kernel.mbRetry THEN res := retry
+					END
+				ELSE*)
+					res := cancel
+				(*END*)
+			ELSE
+				res := ok
+			END
+		UNTIL res # retry
+	END CheckDelete;
+
+	PROCEDURE (f: File) Register (name: Files.Name; type: Files.Type; ask: BOOLEAN; OUT res: INTEGER);
+		VAR b: INTEGER; fname: FullName; fn, nn: ShortName;
+	BEGIN
+		ASSERT(f.state = new, 20); ASSERT(name # "", 21);
+		Append(f.loc.path, name, type, f.loc.maxLen, fname);
+		CheckDelete(fname, f.loc.path, ask,  res);
+		ASSERT(res # 87, 100);
+		IF res = ok THEN
+			IF f.name = "" THEN
+				f.name := fname$;
+				OpenFile(create, f.name, f.ref, res);
+				IF res = ok THEN
+					f.state := exclusive; CloseFile(f, res);
+					fn := SHORT(f.name$);
+				END
+			ELSE
+				f.state := exclusive; CloseFile(f, res);
+				fn := SHORT(f.name$); nn := SHORT(fname$);
+				MoveFile(fn, nn, res);
+				IF res = ok THEN
+					f.name := fname$;
+					fn := SHORT(f.name$);
+				ELSE
+					ASSERT(res # 87, 101);
+					fn := SHORT(f.name$);
+					b := LinLibc.remove(fn);
+				END
+			END
+		END;
+		res := Error(res)
+	END Register;
+		
+	PROCEDURE (f: File) Close;
+		VAR res: INTEGER;
+	BEGIN	(* portable *)
+		IF f.state # closed THEN
+			IF f.state = exclusive THEN
+				CloseFile(f, res) 
+			ELSE
+				CloseFileHandle(f, res)
+			END
+		END
+	END Close;
+
+	(* Locator *)
+	
+	PROCEDURE (loc: Locator) This* (IN path: ARRAY OF CHAR): Locator;
+		VAR new: Locator; i: INTEGER;
+	BEGIN
+		IF path = "" THEN
+			NEW(new); new^ := loc^
+		ELSIF path[0] = "/" THEN	(* absolute path *)
+			new := NewLocator(path);
+			new.rootLen := 0
+		ELSIF (path[0] = "\") OR (path[0] = "/") THEN
+			IF (path[1] = "\") OR (path[1] = "/") THEN	(* network path *)
+				new := NewLocator(path);
+				new.rootLen := 0
+			ELSE
+				NEW(new); new^ := dir.startup^;
+				new.res := invalidName;
+				RETURN new
+			END
+		ELSE
+			NEW(new); Append(loc.path, path, "", loc.maxLen, new.path);
+			i := 0; WHILE new.path[i] # 0X DO INC(i) END;
+			IF (new.path[i-1] = "/") OR (new.path[i-1] = "\") THEN new.path[i-1] := 0X END;
+			new.maxLen := loc.maxLen;
+			new.caseSens := loc.caseSens;
+			new.rootLen := loc.rootLen
+		END;
+		new.res := ok;
+		RETURN new
+	END This;
+
+	(* Reader *)
+
+	PROCEDURE (r: Reader) Base (): Files.File;
+	BEGIN	(* portable *)
+		RETURN r.base
+	END Base;
+
+	PROCEDURE (r: Reader) SetPos (pos: INTEGER);
+		VAR f: File; org, offset, i, count, res: INTEGER; buf: Buffer; 
+	BEGIN
+		f := r.base; ASSERT(f # NIL, 20); ASSERT(f.state # closed, 25);
+		ASSERT(pos >= 0, 22); ASSERT(pos <= f.len, 21);
+		offset := pos MOD bufsize; org := pos - offset;
+		i := 0; WHILE (i # nofbufs) & (f.bufs[i] # NIL) & (org # f.bufs[i].org) DO INC(i) END;
+		IF i # nofbufs THEN
+			buf := f.bufs[i];
+			IF buf = NIL THEN	(* create new buffer *)
+				NEW(buf); f.bufs[i] := buf; buf.org := -1
+			END
+		ELSE	(* choose an existing buffer *)
+			f.swapper := (f.swapper + 1) MOD nofbufs;
+			FlushBuffer(f, f.swapper); buf := f.bufs[f.swapper]; buf.org := -1
+		END;
+		IF buf.org # org THEN
+			IF org + bufsize > f.len THEN buf.len := f.len - org ELSE buf.len := bufsize END;
+			count := buf.len;
+			IF count > 0 THEN
+				IF f.ref = invalid THEN CreateFile(f, res) (* ASSERT(res = ok, 100) *) END;
+				IF f.ref # invalid THEN
+					IF LinLibc.fseek(f.ref, org, LinLibc.SEEK_SET) # 0 THEN
+						res := LinLibc_errno(); HALT(101)
+					END;
+					IF  LinLibc.fread(SYSTEM.ADR(buf.data), 1, count, f.ref) < count THEN
+						res := LinLibc_errno();  HALT(102)
+					END;
+					f.t := Kernel.Time()
+				END
+			END;
+			buf.org := org; buf.dirty := FALSE
+		END;
+		r.buf := buf; r.org := org; r.offset := offset; r.eof := FALSE
+		(* 0<= r.org <= r.base.len *)
+		(* 0 <= r.offset < bufsize *)
+		(* 0 <= r.buf.len <= bufsize *)
+		(* r.offset <= r.base.len *)
+		(* r.offset <= r.buf.len *)
+	END SetPos;
+
+	PROCEDURE (r: Reader) Pos (): INTEGER;
+	BEGIN	(* portable *)
+		ASSERT(r.base # NIL, 20);
+		RETURN r.org + r.offset
+	END Pos;
+
+	PROCEDURE (r: Reader) ReadByte (OUT x: BYTE);
+	BEGIN	(* portable *)
+		IF (r.org # r.buf.org) OR (r.offset >= bufsize) THEN r.SetPos(r.org + r.offset) END;
+		IF r.offset < r.buf.len THEN
+			x := r.buf.data[r.offset]; INC(r.offset)
+		ELSE
+			x := 0; r.eof := TRUE
+		END
+	END ReadByte;
+
+	PROCEDURE (r: Reader) ReadBytes (VAR x: ARRAY OF BYTE; beg, len: INTEGER);
+		VAR from, to, count, restInBuf: INTEGER;
+	BEGIN	(* portable *)
+		ASSERT(beg >= 0, 21);
+		IF len > 0 THEN
+			ASSERT(beg + len <= LEN(x), 23);
+			WHILE len # 0 DO
+				IF (r.org # r.buf.org) OR (r.offset >= bufsize) THEN r.SetPos(r.org + r.offset) END;
+				restInBuf := r.buf.len - r.offset; 
+				IF restInBuf = 0 THEN r.eof := TRUE; RETURN
+				ELSIF restInBuf <= len THEN count := restInBuf
+				ELSE count := len
+				END;
+				from := SYSTEM.ADR(r.buf.data[r.offset]); to := SYSTEM.ADR(x) + beg;
+				SYSTEM.MOVE(from, to, count);
+				INC(r.offset, count); INC(beg, count); DEC(len, count)
+			END;
+			r.eof := FALSE
+		ELSE ASSERT(len = 0, 22)
+		END
+	END ReadBytes;
+
+	(* Writer *)
+
+	PROCEDURE (w: Writer) Base (): Files.File;
+	BEGIN	(* portable *)
+		RETURN w.base
+	END Base;
+
+	PROCEDURE (w: Writer) SetPos (pos: INTEGER);
+		VAR f: File; org, offset, i, count, res: INTEGER; buf: Buffer;
+	BEGIN
+		f := w.base; ASSERT(f # NIL, 20); ASSERT(f.state # closed, 25);
+		ASSERT(pos >= 0, 22); ASSERT(pos <= f.len, 21);
+		offset := pos MOD bufsize; org := pos - offset;
+		i := 0; WHILE (i # nofbufs) & (f.bufs[i] # NIL) & (org # f.bufs[i].org) DO INC(i) END;
+		IF i # nofbufs THEN
+			buf := f.bufs[i];
+			IF buf = NIL THEN	(* create new buffer *)
+				NEW(buf); f.bufs[i] := buf; buf.org := -1
+			END
+		ELSE	(* choose an existing buffer *)
+			f.swapper := (f.swapper + 1) MOD nofbufs;
+			FlushBuffer(f, f.swapper); buf := f.bufs[f.swapper]; buf.org := -1
+		END;
+		IF buf.org # org THEN
+			IF org + bufsize > f.len THEN buf.len := f.len - org ELSE buf.len := bufsize END;
+			count := buf.len;
+			IF count > 0 THEN
+				IF f.ref = invalid THEN CreateFile(f, res) (* ASSERT(res = ok, 100) *) END;
+				IF f.ref # invalid THEN
+					IF LinLibc.fseek(f.ref, org, LinLibc.SEEK_SET) # 0 THEN
+						res := LinLibc_errno(); HALT(101)
+					END;
+					IF  LinLibc.fread(SYSTEM.ADR(buf.data), 1, count, f.ref) < count THEN
+						res := LinLibc_errno();  HALT(102)
+					END;
+					f.t := Kernel.Time()
+				END
+			END;
+			buf.org := org; buf.dirty := FALSE
+		END;
+		w.buf := buf; w.org := org; w.offset := offset
+		(* 0<= w.org <= w.base.len *)
+		(* 0 <= w.offset < bufsize *)
+		(* 0 <= w.buf.len <= bufsize *)
+		(* w.offset <= w.base.len *)
+		(* w.offset <= w.buf.len *)
+	END SetPos;
+
+	PROCEDURE (w: Writer) Pos (): INTEGER;
+	BEGIN	(* portable *)
+		ASSERT(w.base # NIL, 20);
+		RETURN w.org + w.offset
+	END Pos;
+
+	PROCEDURE (w: Writer) WriteByte (x: BYTE);
+	BEGIN	(* portable *)
+		ASSERT(w.base.state # closed, 25);
+		IF (w.org # w.buf.org) OR (w.offset >= bufsize) THEN w.SetPos(w.org + w.offset) END;
+		w.buf.data[w.offset] := x; w.buf.dirty := TRUE;
+		IF w.offset = w.buf.len THEN INC(w.buf.len); INC(w.base.len) END;
+		INC(w.offset)
+	END WriteByte;
+
+	PROCEDURE (w: Writer) WriteBytes (IN x: ARRAY OF BYTE; beg, len: INTEGER);
+		VAR from, to, count, restInBuf: INTEGER;
+	BEGIN	(* portable *)
+		ASSERT(beg >= 0, 21); ASSERT(w.base.state # closed, 25);
+		IF len > 0 THEN
+			ASSERT(beg + len <= LEN(x), 23);
+			WHILE len # 0 DO
+				IF (w.org # w.buf.org) OR (w.offset >= bufsize) THEN w.SetPos(w.org + w.offset) END;
+				restInBuf := bufsize - w.offset;
+				IF restInBuf <= len THEN count := restInBuf ELSE count := len END;
+				from := SYSTEM.ADR(x) + beg; to := SYSTEM.ADR(w.buf.data[w.offset]);
+				SYSTEM.MOVE(from, to, count);
+				INC(w.offset, count); INC(beg, count); DEC(len, count);
+				IF w.offset > w.buf.len THEN INC(w.base.len, w.offset - w.buf.len); w.buf.len := w.offset END;
+				w.buf.dirty := TRUE
+			END
+		ELSE ASSERT(len = 0, 22)
+		END
+	END WriteBytes;
+
+	(* Directory *)
+
+	PROCEDURE (d: Directory) This (IN path: ARRAY OF CHAR): Files.Locator;
+	BEGIN
+		RETURN d.startup.This(path)
+	END This;
+
+	PROCEDURE (d: Directory) New (loc: Files.Locator; ask: BOOLEAN): Files.File;
+		VAR f: File; res: INTEGER; attr: SET; isDir: BOOLEAN; buf: LinLibc.stat_t;
+	BEGIN
+		ASSERT(loc # NIL, 20); f := NIL; res := ok;
+		WITH loc: Locator DO
+			IF loc.path # "" THEN
+				Stat(loc.path, buf, res);
+				IF res # ok THEN
+					IF loc.res = 76 THEN CreateDir(loc.path, res)
+					ELSE CheckPath(loc.path, ask, res)
+					END
+				ELSE
+					ModeToAttr(buf.st_mode, attr, isDir); 
+					IF  ~isDir THEN res := fileExistsErr END
+				END
+			END;
+			IF res = ok THEN
+				NEW(f); f.loc := loc; f.name := "";
+				f.state := new; f.swapper := -1; f.len := 0; f.ref := invalid
+			END
+		ELSE res := invalidNameErr
+		END;
+		loc.res := Error(res);
+		RETURN f
+	END New;
+	
+	PROCEDURE (d: Directory) Temp (): Files.File;
+		VAR f: File;
+	BEGIN
+		NEW(f); f.loc := d.temp; f.name := "";
+		f.state := temp; f.swapper := -1; f.len := 0; f.ref := invalid;
+		RETURN f
+	END Temp;
+	
+	PROCEDURE GetShadowDir (loc: Locator; OUT dir: FullName);
+		VAR i, j: INTEGER;
+	BEGIN
+		dir := startupDir$; i := startupLen; j := loc.rootLen;
+		WHILE loc.path[j] # 0X DO dir[i] := loc.path[j]; INC(i); INC(j) END;
+		dir[i] := 0X
+	END GetShadowDir;
+
+	PROCEDURE (d: Directory) Old (loc: Files.Locator; name: Files.Name; shrd: BOOLEAN): Files.File;
+		VAR res: INTEGER; f: File; ref: LinLibc.PtrFILE; fname: FullName; type: Files.Type; s: BYTE; buf: LinLibc.stat_t;
+	BEGIN
+		ASSERT(loc # NIL, 20); ASSERT(name # "", 21);
+		res := ok; f := NIL;
+		WITH loc: Locator DO
+			Append(loc.path, name, "", loc.maxLen, fname);
+			f := ThisFile(fname);
+			IF f # NIL THEN
+				IF ~shrd OR (f.state = exclusive) THEN loc.res := Error(sharingErr); RETURN NIL
+				ELSE loc.res := ok; RETURN f
+				END
+			END;
+			IF shrd THEN s := shared ELSE s := exclusive END;
+			OpenFile(s, fname, ref, res);
+			IF ((res = fileNotFoundErr) OR (res = pathNotFoundErr)) & (loc.rootLen > 0) THEN
+				GetShadowDir(loc, fname);
+				Append(fname, name, "", loc.maxLen, fname);
+				f := ThisFile(fname);
+				IF f # NIL THEN
+					IF ~shrd OR (f.state = exclusive) THEN loc.res := Error(sharingErr); RETURN NIL
+					ELSE loc.res := ok; RETURN f
+					END
+				END;
+				OpenFile(s, fname, ref, res)
+			END;
+			IF res = ok THEN
+				NEW(f); f.loc := loc;
+				f.swapper := -1; 
+				GetType(name, type);
+				f.InitType(type);
+				ASSERT(ref # invalid, 107);
+				f.ref := ref; f.name := fname$; f.state := s; f.t := Kernel.Time();
+				Stat(f.name, buf, res);
+				f.len := buf.st_size;
+				res := LinLibc.fseek(ref, 0, LinLibc.SEEK_SET);
+			END
+		END;
+		loc.res := Error(res);
+		RETURN f
+	END Old;
+
+	PROCEDURE (d: Directory) Delete* (loc: Files.Locator; name: Files.Name);
+		VAR res: INTEGER; fname: FullName;
+	BEGIN
+		ASSERT(loc # NIL, 20);
+		WITH loc: Locator DO
+			Append(loc.path, name, "", loc.maxLen, fname);
+			Delete(fname, loc.path, res)
+		ELSE res := invalidNameErr
+		END;
+		loc.res := Error(res)
+	END Delete;
+
+	PROCEDURE (d: Directory) Rename* (loc: Files.Locator; old, new: Files.Name; ask: BOOLEAN);
+		VAR res, i: INTEGER; oldname, newname: FullName; f: File; on, nn, tn: ShortName; buf: LinLibc.stat_t;
+	BEGIN
+		ASSERT(loc # NIL, 20);
+		WITH loc: Locator DO
+			Append(loc.path, old, "", loc.maxLen, oldname); Append(loc.path, new, "", loc.maxLen, newname);
+			on := SHORT(oldname$); nn := SHORT(newname$);
+			Stat(oldname, buf, res);
+			IF res = ok THEN
+				f := ThisFile(oldname);
+				IF (f # NIL) & (f.ref # invalid) THEN res := LinLibc.fclose(f.ref); f.ref := invalid END;
+				IF Diff(oldname, newname, loc.caseSens) # 0 THEN
+					CheckDelete(newname, loc.path, ask, res);
+					IF res = ok THEN
+						IF LinLibc.rename(on, nn) = 0 THEN
+							IF f # NIL THEN	(* still in use => update file table *)
+								f.name := newname$
+							END
+						ELSE res := LinLibc_errno()
+						END
+					END
+				ELSE	(* destination is same file as source *)
+					tn := on$; i := LEN(tn$) - 1;
+					REPEAT
+						tn[i] := SHORT(CHR(ORD(tn[i]) + 1));
+						MoveFile(on, tn, res);
+					UNTIL (res # fileExistsErr) & (res # alreadyExistsErr) & (res # 87);
+					IF res = ok THEN
+						MoveFile(tn, nn, res)
+					END
+				END
+			ELSE res := fileNotFoundErr
+			END
+		ELSE res := invalidNameErr
+		END;
+		loc.res := Error(res)
+	END Rename;
+
+	PROCEDURE (d: Directory) SameFile* (loc0: Files.Locator; name0: Files.Name;
+		loc1: Files.Locator; name1: Files.Name
+	): BOOLEAN;
+		VAR p0, p1: FullName;
+	BEGIN
+		ASSERT(loc0 # NIL, 20); ASSERT(loc1 # NIL, 21);
+		WITH loc0: Locator DO Append(loc0.path, name0, "", loc0.maxLen, p0) END;
+		WITH loc1: Locator DO Append(loc1.path, name1, "", loc1.maxLen, p1) END;
+		RETURN Diff(p0, p1, loc0(Locator).caseSens) = 0
+	END SameFile;
+
+	PROCEDURE (d: Directory) FileList* (loc: Files.Locator): Files.FileInfo;
+		VAR diff, res: INTEGER; first, last, info: Files.FileInfo; s: FullName;
+			ss, fname: ShortName; dirp: LinLibc.PtrDIR; dp: LinLibc.PtrDirent; buf: LinLibc.stat_t; tm: LinLibc.tm;
+			isDir: BOOLEAN; attr: SET;
+	BEGIN
+		ASSERT(loc # NIL, 20);
+		first := NIL; last :=NIL;
+		WITH loc: Locator DO
+			ss := SHORT(loc.path);
+			dirp := LinLibc.opendir(ss);
+			IF dirp # LinLibc.NULL THEN
+				dp := LinLibc.readdir(dirp);
+				WHILE dp # NIL DO
+					IF (dp.d_name # ".") & (dp.d_name # "..") & (LEN(dp.d_name$) < LEN(info.name)) THEN
+						fname := ss + "/" + dp.d_name;
+						res := LinLibc.__xstat(3, fname, buf); (* macro expansion of "stat" *)
+						ModeToAttr(buf.st_mode, attr, isDir);
+						IF ~isDir THEN	
+							info := first; last := NIL; s := dp.d_name$;
+							WHILE (info # NIL) & (Diff(info.name, s, loc.caseSens) < 0) DO last := info; info := info.next END;
+							NEW(info);
+							info.name := dp.d_name$;
+							GetType(info.name, info.type);
+							info.length := buf.st_size; 
+							tm := LinLibc.localtime(buf.st_mtime);
+							IF tm # NIL THEN 
+								info.modified.year := tm.tm_year  + 1900;
+								info.modified.month := tm.tm_mon + 1;
+								info.modified.day := tm.tm_mday;
+								info.modified.hour := tm.tm_hour;
+								info.modified.minute := tm.tm_min;
+								info.modified.second := tm.tm_sec
+							END;
+							info.attr := attr;
+							IF last = NIL THEN info.next := first; first := info ELSE info.next := last.next; last.next := info END
+						END
+					END;
+					dp := LinLibc.readdir(dirp)
+				END;
+				res := LinLibc.closedir(dirp)
+			ELSE res := LinLibc_errno()
+			END;
+			(* check startup directory *)
+			IF (loc.rootLen > 0) & ((res = ok) OR (res = fileNotFoundErr) OR (res = pathNotFoundErr)) THEN
+				GetShadowDir(loc, s);
+				ss := SHORT(s$);
+				dirp := LinLibc.opendir(ss);
+				IF dirp # LinLibc.NULL THEN
+					dp := LinLibc.readdir(dirp);
+					WHILE dp # NIL DO
+						IF (dp.d_name # ".") & (dp.d_name # "..") & (LEN(dp.d_name$) < LEN(info.name)) THEN
+							fname := ss + "/" + dp.d_name;
+							res := LinLibc.__xstat(3, fname, buf); (* macro expansion of "stat" *)
+							ModeToAttr(buf.st_mode, attr, isDir);
+							IF ~isDir THEN	
+								info := first; last := NIL; s := dp.d_name$;
+								IF info # NIL THEN diff := Diff(info.name, s, loc.caseSens) END;
+								WHILE (info # NIL) & (diff < 0) DO 
+									last := info; info := info.next; 
+									IF info # NIL THEN diff := Diff(info.name, s, loc.caseSens) END
+								END;
+								IF (info = NIL) OR (diff # 0) THEN
+									NEW(info);
+									info.name := dp.d_name$;
+									GetType(info.name, info.type);
+									info.length := buf.st_size; 
+									tm := LinLibc.localtime(buf.st_mtime);
+									IF tm # NIL THEN 
+										info.modified.year := tm.tm_year  + 1900;
+										info.modified.month := tm.tm_mon + 1;
+										info.modified.day := tm.tm_mday;
+										info.modified.hour := tm.tm_hour;
+										info.modified.minute := tm.tm_min;
+										info.modified.second := tm.tm_sec
+									END;
+									info.attr := attr;
+									IF last = NIL THEN info.next := first; first := info ELSE info.next := last.next; last.next := info END
+								END
+							END
+						END;
+						dp := LinLibc.readdir(dirp)
+					END;
+					res := LinLibc.closedir(dirp)
+				ELSE res := LinLibc_errno()
+				END
+			END;
+			loc.res := Error(res)
+		ELSE loc.res := invalidName
+		END;
+		RETURN first
+	END FileList;
+	
+	PROCEDURE (d: Directory) LocList* (loc: Files.Locator): Files.LocInfo;
+		VAR diff, res: INTEGER; first, last, info: Files.LocInfo; s: FullName; isDir: BOOLEAN; attr: SET;
+			ss, fname: ShortName; dirp: LinLibc.PtrDIR; dp: LinLibc.PtrDirent; buf: LinLibc.stat_t;
+	BEGIN
+		ASSERT(loc # NIL, 20);
+		first := NIL; last :=NIL;
+		WITH loc: Locator DO
+			ss := SHORT(loc.path);
+			dirp := LinLibc.opendir(ss);
+			IF dirp # LinLibc.NULL THEN
+				dp := LinLibc.readdir(dirp);
+				WHILE dp # NIL DO
+					IF (dp.d_name # ".") & (dp.d_name # "..") & (LEN(dp.d_name$) < LEN(info.name)) THEN
+						fname := ss + "/" + dp.d_name;
+						res := LinLibc.__xstat(3, fname, buf); (* macro expansion of "stat" *)
+						ModeToAttr(buf.st_mode, attr, isDir);
+						IF isDir THEN	
+							info := first; last := NIL; s := dp.d_name$;
+							WHILE (info # NIL) & (Diff(info.name, s, loc.caseSens) < 0) DO last := info; info := info.next END;
+							NEW(info);
+							info.name := dp.d_name$;
+							info.attr := attr;
+							IF last = NIL THEN info.next := first; first := info ELSE info.next := last.next; last.next := info END
+						END
+					END;
+					dp := LinLibc.readdir(dirp)
+				END;
+				res := LinLibc.closedir(dirp)
+			ELSE res := LinLibc_errno()
+			END;
+			(* check startup directory *)
+			IF (loc.rootLen > 0) & ((res = ok) OR (res = fileNotFoundErr) OR (res = pathNotFoundErr)) THEN
+				GetShadowDir(loc, s);
+				ss := SHORT(s$);
+				dirp := LinLibc.opendir(ss);
+				IF dirp # LinLibc.NULL THEN
+					dp := LinLibc.readdir(dirp);
+					WHILE dp # NIL DO
+						IF (dp.d_name # ".") & (dp.d_name # "..") & (LEN(dp.d_name$) < LEN(info.name)) THEN
+							fname := ss + "/" + dp.d_name;
+							res := LinLibc.__xstat(3, fname, buf); (* macro expansion of "stat" *)
+							ModeToAttr(buf.st_mode, attr, isDir);
+							IF isDir THEN	
+								info := first; last := NIL; s := dp.d_name$;
+								IF info # NIL THEN diff := Diff(info.name, s, loc.caseSens) END;
+								WHILE (info # NIL) & (diff < 0) DO 
+									last := info; info := info.next; 
+									IF info # NIL THEN diff := Diff(info.name, s, loc.caseSens) END
+								END;
+								IF (info = NIL) OR (diff # 0) THEN
+									NEW(info);
+									info.name := dp.d_name$;
+									info.attr := attr;
+									IF last = NIL THEN info.next := first; first := info ELSE info.next := last.next; last.next := info END
+								END
+							END
+						END;
+						dp := LinLibc.readdir(dirp)
+					END;
+					res := LinLibc.closedir(dirp)
+				ELSE res := LinLibc_errno()
+				END
+			END;
+			loc.res := Error(res)
+		ELSE loc.res := invalidName
+		END;
+		RETURN first
+	END LocList;
+
+	PROCEDURE (d: Directory) GetFileName (name: Files.Name; type: Files.Type; OUT filename: Files.Name);
+	BEGIN
+		Append("", name, type, LEN(filename), filename)
+	END GetFileName;
+
+	(** Miscellaneous **)
+	
+	PROCEDURE (VAR id: Counter) Identified (): BOOLEAN;
+		VAR f: File;
+	BEGIN
+		f := id.obj(File);
+		IF f.state # closed THEN INC(id.count) END;
+		RETURN FALSE
+	END Identified;
+
+	PROCEDURE NofFiles* (): INTEGER;
+		VAR p: ANYPTR; cnt: Counter;
+	BEGIN
+		cnt.typ := SYSTEM.TYP(File);
+		cnt.count := 0; p := Kernel.ThisFinObj(cnt);
+		RETURN cnt.count
+	END NofFiles;
+	
+	PROCEDURE GetModDate* (f: Files.File; VAR year, month, day, hour, minute, second: INTEGER);
+		VAR buf: LinLibc.stat_t; tm: LinLibc.tm;
+	BEGIN
+		ASSERT(f IS File, 20);
+		Stat(f(File).name, buf, res);
+		IF res = ok THEN
+			tm := LinLibc.localtime(buf.st_mtime);
+			IF tm # NIL THEN 
+				year := tm.tm_year  + 1900; month := tm.tm_mon + 1; day := tm.tm_mday;
+				hour := tm.tm_hour; minute := tm.tm_min; second := tm.tm_sec
+			ELSE
+				res := -1
+			END
+		END;
+		IF res # ok THEN year := 0; month := 0; day := 0; hour := 0; minute := 0; second := 0 END
+	END GetModDate;
+	
+	PROCEDURE SetRootDir* (path: ARRAY OF CHAR);
+		VAR i: INTEGER;
+	BEGIN
+		dir.startup := NewLocator(path);
+		dir.startup.rootLen := 0; i := 0;
+		WHILE startupDir[i] # 0X DO INC(i) END;
+		startupLen := i
+	END SetRootDir;
+
+	PROCEDURE GetName (VAR p: ARRAY OF CHAR; VAR i: INTEGER; VAR name, opt: FullName);
+		VAR ch, tch: CHAR; j: INTEGER;
+	BEGIN
+		j := 0; ch := p[i]; tch := " ";
+		WHILE ch = " " DO INC(i); ch := p[i] END;
+		IF (ch = "'") OR (ch = '"') THEN tch := ch; INC(i); ch := p[i] END;
+		WHILE (ch >= " ") & (ch # tch) DO
+			name[j] := ch;
+			IF (ch >= "a") & (ch <= "z") OR (ch >= "à") & (ch <= "ö") OR (ch >= "ø") & (ch <= "þ") THEN ch := CAP(ch)
+			ELSIF ch = "-" THEN ch := "/"
+			END;
+			opt[j] := ch; INC(j); INC(i); ch := p[i]
+		END;
+		IF ch > " " THEN INC(i); ch := p[i] END;
+		WHILE (ch # 0X) & (ch <= " ") DO INC(i); ch := p[i] END;
+		name[j] := 0X; opt[j] := 0X
+	END GetName;
+	
+	PROCEDURE Init;
+		VAR res, i, slp: INTEGER; path, opt: FullName; attr: SET; p: LinLibc.PtrSTR; str: ARRAY 256 OF CHAR;
+			buf: LinLibc.stat_t; isDir: BOOLEAN;
+	BEGIN
+(*
+		TODO: 
+		Instead of using getcwd below to find the local path it would be better to use Kernel.bootinfo.argv[0].
+		But this only works if the PATH variable of the shell is not set to hold the BlackBox directory. In that
+		case all directories in the PATH variable has to be searched for the blackbox executable: 
+			if (argv[0][0] == '/')
+				s = argv[0]
+			else {
+				str = getenv( "PATH" ); len = strlen( str );
+				for ( i = 0, s = 0; i < len; i++ )
+					if ( str[i] == ':' ) {
+						str[i] = '\0';
+					if ( checkpath( str + s, argv[0] ) ) break;
+					else s = i + 1;
+				}
+			}
+*)
+		wildcard := "*"; NEW(dir);
+		str := Kernel.cmdLine$;
+		i := 0; slp := -1;
+		WHILE (str[i] # " ") & (str[i] # 0X) DO 
+			startupDir[i] := str[i]; 
+			IF str[i] = "/" THEN slp := i END; 
+			INC(i) 
+		END;
+		startupDir[i] := 0X; 
+		IF slp < 0 THEN 
+			appName := startupDir;
+			p := NIL;
+			p := LinLibc.getcwd(p, 0);
+			startupDir := p$; 
+			LinLibc.free(SYSTEM.VAL(LinLibc.PtrVoid, p));
+			i := 0;
+			WHILE startupDir[i] # 0X DO INC(i) END;
+			startupLen := i;
+		ELSE
+			i := slp  + 1;
+			WHILE startupDir[i] # 0X DO appName[i - slp - 1] := startupDir[i]; INC(i) END;
+			startupDir[slp] := 0X;
+			startupLen := slp;
+		END;
+		dir.startup := NewLocator(startupDir);
+		dir.startup.rootLen := 0; 
+(*
+		p := NIL;
+		p := LinLibc.getcwd(p, 0);
+		startupDir := p$; LinLibc.free(SYSTEM.VAL(LinLibc.PtrVoid, p));
+		dir.startup := NewLocator(startupDir);
+		dir.startup.rootLen := 0; i := 0;
+		WHILE startupDir[i] # 0X DO INC(i) END;
+		startupLen := i;
+		str := Kernel.cmdLine$;
+*)
+(*
+		i := 0;
+		WHILE (str[i] # " ") & (str[i] # 0X) DO appName[i] := str[i]; INC(i) END;
+		appName[i] := 0X; 
+*)
+		i := 0; res := 1;
+		REPEAT
+			GetName(str, i, path, opt);
+			IF opt = "/USE" THEN 
+				GetName(str, i, path, opt); 
+				Stat(path, buf, res);
+				IF res =ok THEN
+					ModeToAttr(buf.st_mode, attr, isDir);
+					IF isDir THEN res := ok ELSE res := invalidName END
+				END
+			END
+		UNTIL (res = 0) OR (str[i] < " ");
+		IF serverVersion & (res = 0) THEN
+			i := 0; WHILE path[i] # 0X DO INC(i) END;
+			IF (path[i-1] = "/") OR (path[i-1] = "\") THEN DEC(i); path[i] := 0X END;
+			dir.startup := NewLocator(path); 
+			dir.startup.rootLen := SHORT(i)
+		END;
+		dir.temp := NewLocator(LinLibc.P_tmpdir);
+		Files.SetDir(dir)
+	END Init;
+	
+BEGIN
+	Init
+END HostFiles.

+ 1 - 0
BlackBox/Linux/Lin/Rsrc/loader/BlackBox-dl.c

@@ -0,0 +1 @@
+../../../../OpenBSD/Lin/Rsrc/loader/BlackBox-dl.c

+ 1 - 0
BlackBox/Linux/Lin/Rsrc/loader/BlackBox.c

@@ -0,0 +1 @@
+../../../../OpenBSD/Lin/Rsrc/loader/BlackBox.c

+ 1 - 0
BlackBox/Linux/Lin/Rsrc/loader/BlackBox1.c

@@ -0,0 +1 @@
+../../../../OpenBSD/Lin/Rsrc/loader/BlackBox1.c

+ 21 - 0
BlackBox/Linux/Lin/Rsrc/loader/Makefile

@@ -0,0 +1,21 @@
+# This is GNU Makefile
+#    BSD       GNU
+# ${.TARGET}    $@
+# ${.ALLSRC}    $^
+# ${.IMPSRC}    $<
+
+all: lindev BlackBox BlackBox-dl
+
+CFLAGS += -Wall -O0 -g -m32
+
+BlackBox: BlackBox.c
+	${CC} ${CFLAGS} -o $@ $^ -L. -lBB
+
+BlackBox-dl: BlackBox-dl.c
+	${CC} ${CFLAGS} -o $@ $^
+
+lindev: BlackBox1.c
+	${CC} ${CFLAGS} -o $@ $^ -L . -lBB0
+
+clean:
+	rm -f lindev BlackBox BlackBox-dl

+ 1 - 0
BlackBox/Linux/Lin/Rsrc/loader/libBB.so

@@ -0,0 +1 @@
+../../../libBB.so

+ 1 - 0
BlackBox/Linux/Lin/Rsrc/loader/libBB0.so

@@ -0,0 +1 @@
+../../../libBB0.so

BIN
BlackBox/Linux/libBB.so


BIN
BlackBox/Linux/libBB0.so


+ 1 - 0
BlackBox/Linux/lindev

@@ -0,0 +1 @@
+Lin/Rsrc/loader/lindev

+ 1 - 0
BlackBox/OpenBSD/BlackBox

@@ -0,0 +1 @@
+Lin/Rsrc/loader/BlackBox

+ 0 - 0
BlackBox/Lin/Mod/Obsd.Console.odc → BlackBox/OpenBSD/Lin/Mod/Console.odc


+ 1 - 1
BlackBox/Lin/Mod/Obsd.Console.txt → BlackBox/OpenBSD/Lin/Mod/Console.txt

@@ -1,6 +1,6 @@
 MODULE LinConsole;
 
-	(* THIS IS TEXT COPY OF Obsd.Console.odc *)
+	(* THIS IS TEXT COPY OF Console.odc *)
 	(* DO NOT EDIT *)
 
 	IMPORT

+ 0 - 0
BlackBox/Lin/Mod/Obsd.Dates.odc → BlackBox/OpenBSD/Lin/Mod/Dates.odc


+ 1 - 1
BlackBox/Lin/Mod/Obsd.Dates.txt → BlackBox/OpenBSD/Lin/Mod/Dates.txt

@@ -1,6 +1,6 @@
 MODULE HostDates;
 
-	(* THIS IS TEXT COPY OF Obsd.Dates.odc *)
+	(* THIS IS TEXT COPY OF Dates.odc *)
 	(* DO NOT EDIT *)
 
 	IMPORT 

+ 0 - 0
BlackBox/Lin/Mod/Obsd.Dl.txt → BlackBox/OpenBSD/Lin/Mod/Dl.txt


+ 0 - 0
BlackBox/Lin/Mod/Obsd.Kernel.odc → BlackBox/OpenBSD/Lin/Mod/Kernel.odc


+ 1 - 1
BlackBox/Lin/Mod/Obsd.Kernel.txt → BlackBox/OpenBSD/Lin/Mod/Kernel.txt

@@ -1,6 +1,6 @@
 MODULE Kernel;
 
-	(* THIS IS TEXT COPY OF Obsd.Kernel.odc *)
+	(* THIS IS TEXT COPY OF Kernel.odc *)
 	(* DO NOT EDIT *)
 
 	(* A. V. Shiryaev, 2012.09

+ 1 - 0
BlackBox/OpenBSD/Lin/Mod/Kernel_so_init.odc

@@ -0,0 +1 @@
+../../../Linux/Lin/Mod/Kernel_so_init.odc

+ 1 - 0
BlackBox/OpenBSD/Lin/Mod/Kernel_so_init.txt

@@ -0,0 +1 @@
+../../../Linux/Lin/Mod/Kernel_so_init.txt

+ 0 - 0
BlackBox/Lin/Mod/Obsd.Libc.txt → BlackBox/OpenBSD/Lin/Mod/Libc.txt


+ 0 - 0
BlackBox/Lin/Mod/Obsd.linHostFiles.odc → BlackBox/OpenBSD/Lin/Mod/linHostFiles.odc


+ 1 - 1
BlackBox/Lin/Mod/Obsd.linHostFiles.txt → BlackBox/OpenBSD/Lin/Mod/linHostFiles.txt

@@ -1,6 +1,6 @@
 MODULE HostFiles;
 
-	(* THIS IS TEXT COPY OF Obsd.linHostFiles.odc *)
+	(* THIS IS TEXT COPY OF linHostFiles.odc *)
 	(* DO NOT EDIT *)
 
 	IMPORT SYSTEM, Kernel, Files, LinLibc;

+ 0 - 0
c/BlackBox-dl.c → BlackBox/OpenBSD/Lin/Rsrc/loader/BlackBox-dl.c


+ 0 - 0
c/BlackBox.c → BlackBox/OpenBSD/Lin/Rsrc/loader/BlackBox.c


+ 0 - 0
c/BlackBox1.c → BlackBox/OpenBSD/Lin/Rsrc/loader/BlackBox1.c


+ 12 - 4
c/Makefile → BlackBox/OpenBSD/Lin/Rsrc/loader/Makefile

@@ -1,3 +1,11 @@
+# This is BSD Makefile
+#    BSD       GNU
+# ${.TARGET}    $@
+# ${.ALLSRC}    $^
+# ${.IMPSRC}    $<
+
+CFLAGS += -Wall -O0 -g
+
 all: libdlobsdwrap.so lindev BlackBox BlackBox-dl
 
 # libdlobsdwrap.so: universal method of correct access to dl* functions
@@ -6,16 +14,16 @@ all: libdlobsdwrap.so lindev BlackBox BlackBox-dl
 
 # -pthread required to dlopen libraries that depends on pthread
 BlackBox: BlackBox.c
-	${CC} ${CFLAGS} -Wall -O0 -g -o ${.TARGET} ${.ALLSRC} -L. -lBB -pthread
+	${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC} -L. -lBB -pthread
 
 BlackBox-dl: BlackBox-dl.c
-	${CC} ${CFLAGS} -Wall -O0 -g -o ${.TARGET} ${.ALLSRC} -pthread
+	${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC} -pthread
 
 lindev: BlackBox1.c
-	${CC} ${CFLAGS} -Wall -O0 -g -o ${.TARGET} ${.ALLSRC} -L . -lBB0
+	${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC} -L . -lBB0
 
 libdlobsdwrap.so: libdlobsdwrap.c
-	${CC} ${CFLAGS} -Wall -O0 -g -o ${.TARGET} ${.ALLSRC} -fPIC -shared
+	${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC} -fPIC -shared
 
 clean:
 	rm -f lindev BlackBox BlackBox-dl libdlobsdwrap.so

+ 1 - 0
BlackBox/OpenBSD/Lin/Rsrc/loader/libBB.so

@@ -0,0 +1 @@
+../../../libBB.so

+ 1 - 0
BlackBox/OpenBSD/Lin/Rsrc/loader/libBB0.so

@@ -0,0 +1 @@
+../../../libBB0.so

+ 0 - 0
c/libdlobsdwrap.c → BlackBox/OpenBSD/Lin/Rsrc/loader/libdlobsdwrap.c


+ 0 - 0
BlackBox/libBB.so → BlackBox/OpenBSD/libBB.so


+ 0 - 0
BlackBox/libBB0.so → BlackBox/OpenBSD/libBB0.so


+ 1 - 0
BlackBox/OpenBSD/libdlobsdwrap.so

@@ -0,0 +1 @@
+Lin/Rsrc/loader/libdlobsdwrap.so

+ 1 - 0
BlackBox/OpenBSD/lindev

@@ -0,0 +1 @@
+Lin/Rsrc/loader/lindev

+ 6 - 6
BlackBox/build

@@ -1,9 +1,9 @@
 #!/bin/sh
 
 ./run-lindev <<DATA
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Dl.txt')
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Libc.txt')
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Kernel.txt')
+LindevCompiler.Compile('Lin/Mod', 'Dl.txt')
+LindevCompiler.Compile('Lin/Mod', 'Libc.txt')
+LindevCompiler.Compile('Lin/Mod', 'Kernel.txt')
 
 LindevCompiler.Compile('System/Mod', 'Files.txt')
 LindevCompiler.Compile('System/Mod', 'Console.txt')
@@ -12,8 +12,8 @@ LindevCompiler.Compile('System/Mod', 'Strings.txt')
 LindevCompiler.Compile('System/Mod', 'Meta.txt')
 LindevCompiler.Compile('System/Mod', 'Dialog.txt')
 
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Console.txt')
-LindevCompiler.Compile('Lin/Mod', 'Obsd.linHostFiles.txt')
+LindevCompiler.Compile('Lin/Mod', 'Console.txt')
+LindevCompiler.Compile('Lin/Mod', 'linHostFiles.txt')
 
 LindevCompiler.Compile('System/Mod', 'Stores.txt')
 LindevCompiler.Compile('System/Mod', 'Converters.txt')
@@ -96,7 +96,7 @@ LindevCompiler.Compile('', 'HostFonts.txt')
 LindevCompiler.Compile('', 'HostDialog.txt')
 LindevCompiler.Compile('', 'HostWindows.txt')
 # HostDates:
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Dates.txt')
+LindevCompiler.Compile('Lin/Mod', 'Dates.txt')
 
 LindevCompiler.Compile('Cons/Mod', 'Interp.txt')
 

+ 5 - 5
BlackBox/build-lindev

@@ -1,9 +1,9 @@
 #!/bin/sh
 
 ./run-lindev <<DATA
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Dl.txt')
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Libc.txt')
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Kernel.txt')
+LindevCompiler.Compile('Lin/Mod', 'Dl.txt')
+LindevCompiler.Compile('Lin/Mod', 'Libc.txt')
+LindevCompiler.Compile('Lin/Mod', 'Kernel.txt')
 
 LindevCompiler.Compile('System/Mod', 'Files.txt')
 LindevCompiler.Compile('System/Mod', 'Console.txt')
@@ -26,8 +26,8 @@ LindevCompiler.Compile('Lindev/Mod', 'CPV486.txt')
 LindevCompiler.Compile('Lindev/Mod', 'Compiler.txt')
 LindevCompiler.Compile('Lindev/Mod', 'ElfLinker16.txt')
 
-LindevCompiler.Compile('Lin/Mod', 'Obsd.Console.txt')
-LindevCompiler.Compile('Lin/Mod', 'Obsd.linHostFiles.txt')
+LindevCompiler.Compile('Lin/Mod', 'Console.txt')
+LindevCompiler.Compile('Lin/Mod', 'linHostFiles.txt')
 
 ### simple dev interpreter (include LindevCompiler and LindevElfLinker)
 

+ 0 - 1
BlackBox/libdlobsdwrap.so

@@ -1 +0,0 @@
-../c/libdlobsdwrap.so

+ 0 - 1
BlackBox/lindev

@@ -1 +0,0 @@
-../c/lindev

+ 0 - 12
BlackBox/run-BlackBox-dl

@@ -1,12 +0,0 @@
-#!/bin/sh
-
-# ulimit -s 32000
-
-rn=`readlink -f "${0}"`
-d=`dirname "${rn}"`
-
-exe="BlackBox-dl"
-appName=${exe}
-
-# export LD_DEBUG=all
-env LD_LIBRARY_PATH="${d}" CMDLINE="${d}/${appName} `echo ${@}`" "${d}"/${exe}

+ 0 - 1
BlackBox/run-lindev

@@ -1 +0,0 @@
-../c/run-lindev

+ 4 - 0
BlackBox/run-lindev

@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# env LD_LIBRARY_PATH=. env LD_DEBUG=1 ./lindev
+env LD_LIBRARY_PATH=. ./lindev

+ 49 - 0
BlackBox/switch-os

@@ -0,0 +1,49 @@
+#!/bin/sh
+
+none() {
+	if [ -e System/Mod/Kernel.odc -a ! -h System/Mod/Kernel.odc ]; then
+		echo Kernel.odc modified
+		exit 1
+	fi
+
+	rm -rf \
+		System/Mod/Kernel.odc System/Code/Kernel.ocf System/Sym/Kernel.osf \
+		Code/Kernel.ocf Sym/Kernel.osf \
+		Host Win Lin BlackBox blackbox.exe BlackBox.exe *.so lindev
+}
+
+obsd() {
+	ln -s ../../OpenBSD/Lin/Mod/Kernel.odc System/Mod/Kernel.odc
+	ln -s OpenBSD/Lin
+	ln -s OpenBSD/Host
+	ln -s OpenBSD/libBB.so
+	ln -s OpenBSD/libBB0.so
+	cp OpenBSD/BlackBox .
+	cp OpenBSD/lindev .
+	cp OpenBSD/libdlobsdwrap.so .
+}
+
+lin() {
+	ln -s ../../Linux/Lin/Mod/Kernel.odc System/Mod/Kernel.odc
+	ln -s Linux/Lin
+	ln -s Linux/Host
+	ln -s Linux/libBB.so
+	ln -s Linux/libBB0.so
+	ln -s Linux/BlackBox .
+	ln -s Linux/lindev .
+}
+
+case $1 in
+none)
+	none
+	;;
+OpenBSD)
+	none && obsd
+	;;
+Linux)
+	none && lin
+	;;
+*)
+	echo "usage: `basename $0` ( none | OpenBSD | Linux )"
+	;;
+esac

+ 28 - 11
README

@@ -1,5 +1,5 @@
 Oberon Microsystems BlackBox Component Builder (http://www.oberon.ch/)
-Port for OpenBSD/i386
+Port for OpenBSD/i386, Linux/i386
 
 Some significant parts taken from OpenBUGS (http://www.openbugs.info/)
 
@@ -7,11 +7,11 @@ How to build:
 	compile loader executable (BlackBox itself and simple interpreter):
 		libBB*.so must be present (can be built from Windows)
 
-		cd c; make
+		cd BlackBox/`uname -s`/Lin/Rsrc/loader; make
 
 	compile self:
 
-		cd BlackBox; ./clean; ./build-lindev; ./build
+		cd BlackBox; ./switch-os `uname -s`; ./clean; ./build-lindev; ./build
 
 Files:
 	original:
@@ -34,9 +34,9 @@ Files:
 			System/Mod/Console.odc
 			Docu/OpenBUGS-License.odc
 		http://forum.oberoncore.ru/viewtopic.php?f=34&t=1159&sid=3e82517160caa46c64331178c1b61e95:
-			Lin/Mod/Kernel_so_init.odc
+			{Linux,OpenBSD}/Lin/Mod/Kernel_so_init.odc
 	modified:
-		Lin/Mod/Obsd.Kernel.odc:
+		OpenBSD/Lin/Mod/Kernel.odc:
 			1.6-rc6 System/Mod/Kernel.odc, OpenBUGS Lin/Mod/linKernel.odc:
 				OpenBSD specific:
 					Memory management rewritten (based on mmap)
@@ -51,22 +51,38 @@ Files:
 						do not install signal handler for SIGTHR (when executable linked with -pthread)
 				Kernel.cmdLine support:
 					Kernel.INIT (SetCmdLine2)
-		Lin/Mod/Obsd.linHostFiles.odc:
+		Linux/Lin/Mod/Kernel.odc:
+			OpenBSD/Lin/Mod/Kernel.odc modified for Linux
+		OpenBSD/Lin/Mod/linHostFiles.odc:
 			OpenBUGS Lin/Mod/linHostFiles.odc:
 				OpenBSD-specific:
 					size_t
 					__xstat -> stat
 				Kernel.cmdLine support:
 					str := "" -> str := Kernel.cmdLine$
-		Lin/Mod/Obsd.Console.odc:
+		Linux/Lin/Mod/linHostFiles.odc:
+			OpenBUGS Lin/Mod/linHostFiles.odc:
+				Kernel.cmdLine support:
+					str := "" -> str := Kernel.cmdLine$
+		OpenBSD/Lin/Mod/Console.odc:
 			OpenBUGS Lin/Mod/Console.odc:
 				stdin -> SYSTEM.ADR(__sF[0])
-		Lin/Mod/Obsd.Libc.txt:
+		Linux/Lin/Mod/Console.odc:
+			OpenBUGS Lin/Mod/Console.odc
+		OpenBSD/Lin/Mod/Libc.txt:
 			OpenBUGS Lin/Mod/Libc.odc:
 				OpenBSD-specific
-		Lin/Mod/Obsd.Dates.odc:
+		Linux/Lin/Mod/Libc.odc:
+			OpenBUGS Lin/Mod/Libc.odc:
+				PROT_*, MAP_* O_* CONSTs added
+				open, close, read, write, mmap, munmap, mprotect, getenv functions added
+		Linux/Lin/Mod/Dl.odc:
+			OpenBUGS Lin/Mod/Dl.odc
+		OpenBSD/Lin/Mod/Dates.odc:
 			HostDates, from http://oberoncore.ru/:
 				OpenBSD-specific
+		Linux/Lin/Mod/Dates.odc:
+			HostDates, from http://oberoncore.ru/
 		Lindev/Mod
 			CP*
 				BlackBox 1.6-rc6 Dev CP* modified to not depend on Dates, Texts etc.
@@ -78,8 +94,9 @@ Files:
 		Cons/Mod
 			Interp.odc: console interpreter
 			Compiler.odc: console interface to Dev compiler
-		libBB.so: compiled and linked OpenBSD shared library to run BlackBox
-		libBB0.so: compiled and linked OpenBSD shared library to run simple development interpreter
+
+		{OpenBSD,Linux}/libBB.so: compiled and linked shared library to run BlackBox
+		{OpenBSD,Linux}/libBB0.so: compiled and linked shared library to run simple development interpreter
 
 		Views.odc: minimal Views implementation required to compile StdInterpreter
 		StdLog.odc: alternative StdLog implementation to not depend on GUI

+ 0 - 1
c/libBB.so

@@ -1 +0,0 @@
-../BlackBox/libBB.so

+ 0 - 1
c/libBB0.so

@@ -1 +0,0 @@
-../BlackBox/libBB0.so

+ 0 - 4
c/run-lindev

@@ -1,4 +0,0 @@
-#!/bin/sh
-
-# env LD_LIBRARY_PATH=. env LD_DEBUG=1 ./lindev
-env LD_LIBRARY_PATH=. ./lindev