//MINIT0.BCPL First init
//	Last edited: 21 October 1981

// This file is loaded with the program.  After execution, its storage
// is added to free storage.  On "Midas/I", initialize Midas; on
// "Midas/R" (Maxc2 Midas only), resume from previous AltIO call.
// Otherwise, initialize Midas from the state file.

get "sysdefs.d"
get "streams.d"
get "altofilesys.d"
get "disks.d"	//for def of fillInDA
get "mdecl.d"
get "mcommon.d"
get "overlays.d"

external [
// OS
	SysErr; MoveBlock; SetBlock; Zero; fpSysDir; OpenFile
	CreateDiskStream; Closes; Gets; WriteBlock; Endofs
	lvUserFinishProc; Noop; Junta; GotoLabel; CallersFrame
	InitializeZone; sysZone; lvSysZone
	keys; CreateKeyboardStream

// OVERLAYSINIT
	OverlayScan

// MDI
	LookupEntries

// GACHA10
	FontP

// MIDAS
	InitRes; MidasFinish; MidasSwat
	lvFinishProc; ElapsedTime; SysZoneSize; StackSize
	TimeJunta; TimeLoadRam; TimeJunkInit; TimeLookup1; TimeCreateFiles
	TimeOvScan; TimeLookup2; TimeQFiles; CodeOS; StorageSize
	AvailBlockSize; BBblockSize

// MASM
	Puts; Resets; Wss; VertIntCode; SelfRel; GetStorage; GetEvenStorage

// MDATA
	MidasCFA

// MOVERLAY
	KillOverlays; OvTable

// MTXTBUF
	InputStream; InputTextBuffer; TxtBNewChar

// MSYM
	TVtoString; @StringVec; Map; NQuickFiles; FileBlock

// MDISP
	MakeDispZoneAvail; ZoneErr
	SaveData1; SaveData2; SaveData3; SavervDASTART; SavedDASTART
	LineCtrlBlockPtrsVector; AvailBlock; BBblock
	FontCharWidth; AvailBlockNLines
	NwdsPerScanLine; StandardLineHeight; BitBufferLen

// MRGN
	ScreenTV; ScreenLineDirty; RegionTable; ControlV
	SelectedRegion; CharInputRoutine

// MMPRGN
	MPDs; @MPDVVec

// MMENU
	@ItemV; ItemStream; SkipName; EscInputText; TimeStartAction

// MCMD
	RestoreState; CmdCommentStream; CmdCS1; NPrograms; ProgramAct
	NReadCFiles; ReadCAct

// MGO
	CallAVec

// MDEBUG
	Vec60

// MINIT1
	MakeDisplayLine; MakeTVS; GetHStorage; GetZStorage; NewRegion

// xxACTIONS
	ActionBlock; LastAction; NHWCFActions; HWCFActions

// Machine dependent
	InitHardware1; @ScreenHeight; @ScreenWidth
	@REGNAM; @REGFORMS; @NREGS; @MEMNAM; @MEMFORMS; AltMInput; @NMEMS
	MachVersion

//Defined here
	Init0; Init0B; CopyTemplate; @MBlock
	Storage; EndStorage; StateBlock; StatePtr; StateEnd
	BlockStoreFP; FixUpFP; ErrsFP; RunProgFP; DtachFP
//	MidasRFP
	@ACTS; RelocTable; MStatus; CmdCS0Vec; CmdCS1Vec
	NNonOvBitBuffers; FirstNonOvLine; FirstLCB; SkipScanLines
	FirstStatic; LastStatic; NStatics; StateBlockSize
	ProgramStream; TimeStream
]

static [
	FirstStatic	// Loc of first static from Layout vector
	LastStatic	// Last static from Layout vector
	NStatics
	StateBlockSize = #40	//> no. saved page zero statics*2
	Storage; EndStorage; StateBlock; StatePtr = 0; StateEnd
	RelocTable	// Pointer to vector of init procedures from Layout
			// vector (RelocTable!0 has no. reloc pairs)
	Switch		// Command line switch to program
	BlockStoreFP; FixUpFP; ErrsFP; RunProgFP; DtachFP
//	MidasRFP
	@MBlock; MStatus; CmdCS0Vec; CmdCS1Vec
	ProgramStream; TimeStream; CopyTemplate; @ACTS
	NNonOvBitBuffers; FirstNonOvLine; FirstLCB; LCBSpace
	Leading = 1; SkipScanLines = 130
	ExtraBitBuffers = -3	//Should be ge 1 - no. blank screen lines
]

manifest [
	codePtr = #335
	NFNames = 5		// Number of names being looked up
	NumOverlays = 37	// Max number of overlays (was 35 on
				// 28 October 1979 for Dorado Midas)
//	MapSize = 2*(MaxBlockPages+1)+13+(size FP/16)	//For ISF package
	OvTSize = (ODsize+1)*NumOverlays+12
	MaxQuickFiles = 60	// Maximum no. files in table
]

let Init0(Layout,userParams,CFA) be
[	FirstStatic = Layout!26
	LastStatic = Layout!27
	NStatics = LastStatic-FirstStatic+1
	RelocTable = Layout!31
	Switch = userParams!1
	CopyTemplate = Noop	//Needed by levStreams
	MBlock = MoveBlock	//Use zrel call to this common subr.
//Save Midas.run CFA across Junta for OverlayScan
	MBlock(MidasCFA,CFA,lCFA)
//Convert assembled-in self-relative pointers to absolute
	for I = ActionBlock to LastAction by size Action/16 do
		I>>Action.Name = I>>Action.Name+I
	LastAction = LastAction+(size Action/16)
	let Action = HWCFActions
//Args for HWActions are string pointers to file names
	for I = 1 to NHWCFActions do
	[ Action>>Action.Arg = Action>>Action.Arg+(lv Action>>Action.Arg)
	  Action = Action+(size Action/16)
	]
	for I = 0 to NREGS-1 do
	[ REGNAM!I = SelfRel(REGNAM+I)
	  if REGFORMS!I ne 0 then REGFORMS!I = SelfRel(REGFORMS+I)
	]
	for I = 0 to NMEMS-1 do
	[ MEMNAM!I = SelfRel(MEMNAM+I)
	  if MEMFORMS!I ne 0 then MEMFORMS!I = SelfRel(MEMFORMS+I)
	]
//Make length error-checks on the machine-description tables
	if (MEMNAM-REGNAM) ne NREGS*6 then MidasSwat(RTablesInconsistent)
	if (AltMInput-MEMNAM) ne NMEMS*7 then MidasSwat(MTablesInconsistent)
	Junta(levStreams,Init0A)
]


and Init0A(nullArg) be
[	ElapsedTime(lv TimeJunta)
	CodeOS = -(lv nullArg)	//Approximate size of OS
//Storage is initialized here rather than in Init0B because Init0B
// uses considerable stack space, all wasted when the new stack is
// created.  Init0A doesn't have much stack space.
	Storage = rv codePtr
	EndStorage = (lv nullArg)-4-StackSize
	StorageSize = EndStorage-Storage	//Orig. size for stats
	rv codePtr = EndStorage
//The ZoneErr static, normally 0, can be set to CallSwat or SysErr
//to invoke zone checking.
	sysZone = InitializeZone(GetStorage(SysZoneSize),SysZoneSize,
		SysErr,ZoneErr)
	rv lvSysZone = sysZone
	keys = CreateKeyboardStream()
// Init0B returns true if full initialization should be done.
// GotoLabel is required here to prevent MidasSwat() by ReleaseOverlay()
	GotoLabel(CallersFrame(),InitRes)
]

and Init0B(TempStorage) be
[
//*Replaced this stuff by making GACHA10.AL into a .br file
//	let FontStream = CreateDiskStream(FontFP,ksTypeReadOnly)
//	let SizeFont = (FileLength(FontStream)+1) rshift 1
//	PositionPage(FontStream,1); FontP = GetStorage(SizeFont)+2
//	ReadBlock(FontStream,FontP-2,SizeFont); Closes(FontStream)
//	StorageFont = SizeFont	//Was 2170 for gacha10.al
//	ElapsedTime(lv TimeFont)
//Max char width = exact if fixed pitch font
	FontCharWidth = (FontP-1)>>rh
	NwdsPerScanLine = ((ScreenWidth*FontCharWidth-1) rshift 4)+1
	StandardLineHeight = FontP!(-2) & 177776B

//Initialize LCB's (line control blocks) and turn off the display
//Do this first so that the machine will run fast during rest of init.
	LineCtrlBlockPtrsVector = GetStorage(ScreenHeight)-1
	LCBSpace = GetEvenStorage((ScreenHeight+1)*(size LCB/16))
// create blank space at top of screen
	FirstLCB = GetFreeDCB(SkipScanLines rshift 1)
// now set up NLines
	let LCB = nil
	for L = 1 to ScreenHeight do
	[ LCB = GetFreeDCB(StandardLineHeight rshift 1)
	  LineCtrlBlockPtrsVector!L = LCB
	]
	LCB>>LCB.Sepr.Link = 0
	SaveData1 = IntVec!VertIntChan
	SaveData2 = DASTART!1
	SaveData3 = rv IntActive
	SavervDASTART = rv DASTART	//Saved for exit from Midas
	IntVec!VertIntChan = VertIntCode
	DASTART!1 = (DASTART!1) % (1 lshift (VertIntChan))
	rv IntActive = (rv IntActive) logor (1 lshift VertIntChan)
//Midas comes up with the display off until the end of the Com.CM
//command file execution.  The bit buffers remain in OverlayZone
//until after the first command in the command file is executed.
	SavedDASTART = FirstLCB; rv DASTART = 0
	lvFinishProc = @lvUserFinishProc
	@lvUserFinishProc = MidasFinish

	BitBufferLen = StandardLineHeight * NwdsPerScanLine
//The register menu lines become the OverlayZone.  Lines below that
//are put in service by Init2.
	let OvLines = ScreenHeight-11
	NNonOvBitBuffers = 11 + ExtraBitBuffers
	FirstNonOvLine = OvLines+1
	AvailBlockNLines = OvLines
	BBblockSize = (BitBufferLen+2) * (ScreenHeight + ExtraBitBuffers)
	AvailBlockSize = OvLines*(BitBufferLen+2)
	BBblock = GetEvenStorage(BBblockSize)
	AvailBlock = BBblock+BBblockSize-AvailBlockSize

	MStatus = GetZStorage(size MStatus/16)	//For RunProg, Dtach
	ACTS = GetStorage(100)	//For actions using alternate command menus
	Vec60 = GetStorage(60)	//For SaveDGen and RestoreDGen in MDEBUG
	StringVec = GetStorage(129)	//For TVtoString and MLOAD
	CallAVec = GetStorage(3); SetBlock(CallAVec,-1,3)	//For MGO
	TimeStartAction = GetStorage(2)	//For MMENU

//First part of init for MRGN
	ScreenLineDirty = GetHStorage(ScreenHeight)
	SetBlock(ScreenLineDirty+1,true,ScreenHeight)
	ScreenTV = GetHStorage(ScreenHeight)
	Zero(ScreenTV+1,ScreenHeight)
//Temporarily use vec's for these two; then copy these to real storage
//if Midas/I.  This avoids saving the storage on the state file and
//allows InputTextBuffer to be written on RunProg.
	let Rtab,CVtab = vec MaxNRegions,vec 80
	Zero(Rtab,MaxNRegions); Zero(CVtab,80)
	RegionTable,ControlV = Rtab,CVtab
	SelectedRegion = NewRegion(size Rgn/16,0,0,0,ScreenHeight,
		ScreenWidth,NopRgn)
	let W = ScreenWidth-1
//MakeDisplayLine args are lvStream,Line,Height,Width,FirstC, where
//Lines are numbered from 1 and chars from 0.  A pointer to the TV for
//the line is returned.
	MakeDisplayLine(lv ProgramStream,ScreenHeight-10,1,50,0)
	MakeDisplayLine(lv TimeStream,ScreenHeight-10,1,W-50,50)
	CmdCS0Vec = MakeDisplayLine(lv CmdCommentStream,ScreenHeight-8,1,W,0)
	CmdCS1Vec = MakeDisplayLine(lv CmdCS1,ScreenHeight-7,1,W,0)
	InputTextBuffer =
	  MakeDisplayLine(lv InputStream,ScreenHeight-1,1,W,0)
	CharInputRoutine = TxtBNewChar

//First part of init for MMENU
	EscInputText = GetZStorage(ScreenWidth+1)
	SkipName = GetStorage(11)
	MakeTVS(lv ItemStream,lv ItemV)
	MakeTVS(lv MPDs,lv MPDVVec)

	ElapsedTime(lv TimeJunkInit)

	InitHardware1()
	Storage = InitHardware1+1000B	//1000B kludge bypasses MachVersion
	ElapsedTime(lv TimeLoadRam)

//Build a table of file names to be looked up in the System directory
	let SysDirStream = CreateDiskStream(fpSysDir,ksTypeReadOnly)
//NFNames must be .le. MaxQuickFiles
	let NV,SV = vec MaxQuickFiles,vec MaxQuickFiles
	let FileDV = GetStorage(lDV*NFNames)
	SetupFPN(lv RunProgFP,NV,SV,0,FileDV,"MIDAS.RUNPROG",1)
	SetupFPN(lv DtachFP,NV,SV,1,FileDV,"MIDAS.DTACH",1)
	SetupFPN(lv BlockStoreFP,NV,SV,2,FileDV,"SWATEE",0)
//Instead of SWATEE, can use:
//	SetupFPN(lv BlockStoreFP,NV,SV,2,FileDV,"MIDAS.SYMTAB",MaxBlockPages)
	SetupFPN(lv FixUpFP,NV,SV,3,FileDV,"MIDAS.FIXUPS",1)
	SetupFPN(lv ErrsFP,NV,SV,4,FileDV,"MIDAS.COMPARE",1)
//No longer do these two
//	SetupFPN(lv FontFP,NV,SV,5,FileDV,"GACHA10.AL",0)
//	SetupFPN(lv MidasRFP,NV,SV,6,FileDV,"MIDAS.RESUME",-1)
// LookupEntries uses .85 + .03/file seconds with ~240 files in directory
// Use storage at the low end of the block used by GetStorage
	let Undefined = LookupEntries(SysDirStream,NV,FileDV,NFNames,
		true,BBblock,BBblockSize)
	ElapsedTime(lv TimeLookup1)

	Map = GetStorage(MaxBlockPages+1)
	test Undefined ne 0
	ifso Switch = $I	//Force Midas/I
	ifnot
	[ Map!0 = BlockStoreFP>>FP.leaderVirtualDa
	  SetBlock(Map+1,fillInDA,MaxBlockPages)
	]

//Show last editing dates
	Wss(ProgramStream,"Midas 10/21/81"); Wss(ProgramStream,MachVersion)

//Initialize for SaveState/RestoreState
//Storage allocated after this point will be saved/restored on/from the
//state file(s)
	MakeDispZoneAvail()
	StateEnd = EndStorage
	switchon Switch & not 40B into
	[
case 0:	  Closes(SysDirStream)	//No switch = RestoreState
	  RestoreState(DtachFP,false)	//Doesn't return
//case $R: Closes(SysDirStream)
//	  RestoreState(MidasRFP,false)
default: MidasSwat(BadSwitch)
case $I: endcase
	]

	StateBlock = GetStorage(StateBlockSize)
//Use BBblock for scratch storage because it is the largest hunk
//of storage available at this time--but have to rebuild OverlayZone
//because of this.
	if OverlayScan(lv MidasCFA>>CFA.fp,GetStorage(OvTSize),OvTSize,
		lv MidasCFA>>CFA.fa,BBblock,BBblockSize) < 0 then
		MidasSwat(OvlScanFailure)
	OvTable = GetZStorage(NumOverlays*2+1); OvTable!0 = 1
	ElapsedTime(lv TimeOvScan)

	MakeDispZoneAvail()
	if Undefined ne 0 do
	[ for I = 0 to NFNames-1 do
	  [ if FileDV!0 eq 0 do
	    [ let Name,npgs = NV!I,SV!I
	      if npgs eq 0 then MidasSwat(NonXFile,Name)
	      Zero(FileDV,lDV)
	      if npgs ne -1 do
	      [	let scratch = vec #400	//Now write the file
		let S = OpenFile(Name,ksTypeWriteOnly,wordItem,verNew,
			FileDV+(offset DV.fp/16))
		test S ne 0
		ifso
		[ for i = 1 to npgs do WriteBlock(S,scratch,#400)
		  Closes(S)
		]
		ifnot MidasSwat(CreateFailed,Name)
	      ]
	    ]
	    FileDV = FileDV+lDV
	  ]
	  Map!0 = BlockStoreFP>>FP.leaderVirtualDa
	  SetBlock(Map+1,fillInDA,MaxBlockPages)
	  KillOverlays()
	]
	ElapsedTime(lv TimeCreateFiles)

//Build these FP's in TempStorage which is the CFileStack vec passed
//through Init1(..) to Init0B(..) from InitRes(..).
//MIDAS.MIDAS is executed to setup state files for Dtach and RunProg
//actions.
	SetupFPN(lv FileDV,NV,SV,0,TempStorage,"MIDAS.MIDAS",0)
	let MProgFP,UProgFP = nil,nil
	let MProgS,UMProgS = "MIDAS.PROGRAMS","MIDAS.USERPROGRAMS"
	SetupFPN(lv MProgFP,NV,SV,1,TempStorage,MProgS,0)
	SetupFPN(lv UProgFP,NV,SV,2,TempStorage,UMProgS,-1)
	Undefined = LookupEntries(SysDirStream,NV,TempStorage,3,
		true,BBblock,BBblockSize)
	let HaveUserPrograms = true
	if Undefined ne 0 do
	[ if TempStorage!(lDV+lDV) eq 0 then HaveUserPrograms = false
	  for I = 0 to 1 do
	  [ if TempStorage!(lDV*I) eq 0 then MidasSwat(NonXFile,NV!I)
	  ]
	]
	ElapsedTime(lv TimeLookup2)

//Read "Midas.Programs" and "Midas.UserPrograms" treating the names
//there as follows:
//   a name containing no "." is made into a "RunProg" menu item
//   if name.midas exists, and both name.midas and name.mb
//   are entered into the QuickOpenFile table;
//   if the name contains a ".", it is only entered into the QuickOpenFile
//   table.
//In either case no entry is made in the QuickOpenFile table unless the
//file exists.
//The algorithm below puts pointers to ".Midas" files at the low end
//of NV and to ".mb" and other files at the high end
	let midasPtr,mbPtr = 0,MaxQuickFiles
	SetupMidasFiles(MProgFP,MProgS,NV,SV,lv midasPtr,lv mbPtr)
	if HaveUserPrograms do
	[ SetupMidasFiles(UProgFP,UMProgS,NV,SV,lv midasPtr,lv mbPtr)
	]
//Now pack NV for LookupEntries
	let NFNames = midasPtr+MaxQuickFiles-mbPtr
	MBlock(NV+midasPtr,NV+mbPtr,MaxQuickFiles-mbPtr)
	let DV = vec MaxQuickFiles*lDV
	Undefined = LookupEntries(SysDirStream,NV,DV,NFNames,
		true,BBblock,BBblockSize)
	Closes(SysDirStream)
	MakeDispZoneAvail()
	NQuickFiles = NFNames - Undefined
	let FBsize = NQuickFiles*lDV; FileBlock = GetZStorage(FBsize)
	ProgramAct = GetZStorage(midasPtr)	//Table of names defined as
					//actions by MINIT2
	let FBPtr = 0
	ReadCAct,NReadCFiles,NPrograms = ProgramAct+midasPtr,0,0
	for I = 0 to NFNames-1 do
	[ if DV!0 ne 0 do
	  [ let Str = NV!I; let StrSize = (Str>>lh rshift 1)+1
	    DV!0 = Str; MBlock(FileBlock+FBPtr,DV,lDV); FBPtr = FBPtr+lDV
	    if FBPtr > FBsize then MidasSwat(LUEBug)
	    if I < midasPtr do
	    [ let PStr = GetStorage(StrSize-3)	//Truncate ".Midas"
	      MBlock(PStr,Str,StrSize-3)
	      PStr>>lh = Str>>lh - 6
	      test SV!I
	      ifso
	      [ ReadCAct = ReadCAct-1; NReadCFiles = NReadCFiles+1
	        rv ReadCAct = PStr
	      ]
	      ifnot
	      [ ProgramAct!NPrograms = PStr; NPrograms = NPrograms+1
	      ]
	    ]
	  ]
	  DV = DV+lDV
	]
	ElapsedTime(lv TimeQFiles)

	RegionTable = GetStorage(MaxNRegions)
	MBlock(RegionTable,Rtab,MaxNRegions)
	ControlV = GetStorage(ScreenHeight+1)
	MBlock(ControlV,CVtab,ScreenHeight+1)
	Storage = Init0
]


and SetupFPN(lvFP,NV,SV,X,PrVec,Name,Size) be
[	NV!X = Name; SV!X = Size
	rv lvFP = PrVec+(offset DV.fp/16)+lDV*X
]


and SetupMidasFiles(FP,Str,NV,SV,lvmidasPtr,lvmbPtr) be
[	let S = CreateDiskStream(FP,ksTypeReadOnly,charItem)
	if S eq 0 then MidasSwat(LUEBug)
	while not Endofs(S) do
	[ Resets(ItemStream); let DotFlag,StarFlag = false,false
	  until Endofs(S) do
	  [ let C = Gets(S)
	    switchon C into
	    [
case $**:	StarFlag = true
case $,: case $ : case $*N: break	//Separators
case $.:	DotFlag = true
default:	if (C < 40B) % (C > 176B) then
			MidasSwat(IllegalChars,Str)
		Puts(ItemStream,C)
case 0:		loop
	    ]
	  ]
	  if ItemV!0 eq 0 then loop	//Just separators
	  test DotFlag
	  ifso
	  [ lvmbPtr!0 = lvmbPtr!0-1
	    NV!(lvmbPtr!0) = MoveString(TVtoString(ItemV))
	  ]
	  ifnot
	  [ let NameEnd = ItemV!0; Wss(ItemStream,".MIDAS")
	    NV!(lvmidasPtr!0) = MoveString(TVtoString(ItemV))
	    SV!(lvmidasPtr!0) = StarFlag
	    lvmidasPtr!0 = (lvmidasPtr!0)+1
	    unless StarFlag do
	    [ ItemV!0 = NameEnd; Wss(ItemStream,".MB")
	      lvmbPtr!0 = lvmbPtr!0-1
	      NV!(lvmbPtr!0) = MoveString(TVtoString(ItemV))
	    ]
	  ]
	  if lvmbPtr!0 le lvmidasPtr!0 then
		MidasSwat(TooManyNames,Str)
	  loop
	]
	Closes(S)
]


and MoveString(String) = valof
[	let Size = (String>>lh rshift 1)+1
	let DestStr = GetStorage(Size)
	MBlock(DestStr,String,Size)
	resultis DestStr
]


and GetFreeDCB(Hover2) = valof
[	let LCB = LCBSpace
	LCBSpace = LCBSpace+(size LCB/16)
//DCB for regular stuff
	LCB>>LCB.Line.Link = LCB+(size dcb/16)
	LCB>>LCB.Line.BufC = HTab lshift 8
	LCB>>LCB.Line.Buffer = 0	//= BitBuffer+2 if bit buffer
	LCB>>LCB.Line.Height = Hover2
//DCB for line separation
	LCB>>LCB.Sepr.Link = LCBSpace
	LCB>>LCB.Sepr.BufC = HTab lshift 8
	LCB>>LCB.Sepr.Buffer = 0
	LCB>>LCB.Sepr.Height = Leading
	resultis LCB
]