// SpruceInit.Bcpl Spruce Spooler Initialization // errors 200 // get "Spruce.d" get "SpruceInLdOutLd.d" get "SprucePrinters.d" get "SpruceDoc.d" get "SpruceMisc.d" get "SpruceFiles.d" get "AltoFileSys.d" external // defined here [ SpruceInit ] external // external [ //Spruce Sprouller Spruce // SpruceUtils SpruceUserFinishProc SpruceCondition FSGetX FSInit FillInNames InitRam SetRMR // Spruce Files InitSpruceFile ResetSpruceFile CreateSpruceFile // User Post InitUser //INSTALL SpruceInstall SetupDrive // CheckPoints CheckPoint OpenCheckPointFile RestoreFromCheckPoint InitCheckZone ActOnEntry //Used for initialization of files, etc. -- removed by Junta Junta MyFrame //Spooler, Queue AddToQueue CleanupQueue InitSpool // Spruce Ml MulDiv; InitFrameRuntime; SetupFrameFinishProc //ALLOC AddToZone //GP ReadParam SetupReadParam // SpruceInUtil CreateFPRD StatusOf31s MakeValidSpruceFile GetLogoInfo //SpruceUtils Reclaim //OS MoveBlock Zero lvUserFinishProc lvSwatContextProc sysDisk InLd OutLd CallSwat InitializeZone CreateDisplayStream Closes OpenFile ReadCalendar ShowDisplayStream EnableInterrupts DisableInterrupts StartIO //TFS TFSInit TFSSetDisk TFSSwatContextProc //FLOAT FLDI; FML; FTR // Context InitializeContext // Queue Enqueue Dequeue //Template PutTemplate // KBD KBDinit //LoadRAM LoadRam // statics DoFileMeter DoMeter Debug DebugSystem Verbose Which DoEtherReport xmFonts UseMicroCode Version MinorVersion SprintVersion Report PressServer // true or false (stand-alone) tridentDisk tridentDrive tridentUsed statusOf31s drive1Disk SpruceZone CpZone sysZone sysFont lvSysZone dsp; firstDCB //firstDCB defined in Spruce.bcpl keys OverlayBottom OverlayTop PermanentBottom SpruceSavedUFP savedSCP ctxQ UserName inMsg; outMsg sprintFPRD spruceFPRD timeUp BandFile CheckPointFile RunFile SpoolFile QueueFile PressFile // LogFile ErrorFile printDoc checkZoneVec printing; spooling reasonVec numFilesSpooled SproullerQ pressFileIndex seed SpoolVec LocalDocsVec BinCounters; NumBins printerDevice Capabilities PRamImage ResolutionB ResolutionS PaperDimensionB PaperDimensionS nVisibleBands FA ] // Imported from sysdefs.d (no room) manifest [ levBFSbase = 5 lInLdMessage = 19 ] // File-wide structure and manifest declarations. static [ MAINStackSize = 2200 // big enough on 1-3-78 InstallStackSize = 2000 BASEStackSize = 700 // initial post-junta stack, big enough September 18, 1978 // ~~ cld be released somehow after use numLocalDocs ] // ------------------------------------------------------ let SpruceInit(userParams, runCfa) = valof // ------------------------------------------------------ // Spruce initialization is done in two major phases: pre- and post-junta. In the early phase, // perform activities requiring the doomed OS components. Install if required (see SpruceInstall()), // initialize memory structures, including the control RAM, prepare the checkpoint file (much of this // done in SpruceInstall()), check consistency with the current printing (Sprint) system. // Then parse the command line for files to print, printer commands to perform, and installation // parameters to override (most of this is vestigial in the server version). // Finally, perform computations based on the installation parameters, checkpoint the derived values // for preservation over the junta, and perform same. sysDisk handling is eccentric because it must be // available to reaccess the checkpoint file. Most of the hair is due to the memory discontinuities // associated with the junta. [ PutTemplate(dsp, "Spruce Server $D.$D*N", Version, MinorVersion) //See if we are installing. //Install if CheckPoint file version statics are zero, or /i switch specified. let doInstall=false for i=1 to 10 switchon CAPS(userParams!i) into // global switches repeated here [ case $I: case $i: doInstall=true case 0: break ] // load RAM, set up checkpoint file, perhaps install (then no return) SpruceInstall(doInstall, runCfa) let initEnd = OverlayTop OverlayTop = SpruceInstall // Toss out installation code AddToZone(SpruceZone, OverlayTop, initEnd-OverlayTop) FSInit() SpruceSavedUFP=@lvUserFinishProc @lvUserFinishProc=SpruceUserFinishProc // restore tasks to ROM SetupFrameFinishProc() savedSCP = @lvSwatContextProc @lvSwatContextProc = TFSSwatContextProc unless SprintVersion do [ PutTemplate(dsp, "Sprint must be installed before Spruce") finish ] unless Version eq SprintVersion do [ let str = Version>SprintVersion? "Sprint", "Spruce" PutTemplate(dsp, "$S.Run is too old; please fetch new version and reinstall*N", str) finish ] // Obtain important statics as modified during installation RestoreFromCheckPoint(LEVSharedInstStatics, LEVInstallationStatics) sprintFPRD = CreateFPRD("Sprint.Boot", false) unless sprintFPRD do [ PutTemplate(dsp, "Sprint.Boot not found; please install Sprint and restart*N"); finish ] // Remaining global switches, used to override installation defaults. let str=vec 20 let sw=vec 10 SetupReadParam(str, sw) let deb = DebugSystem // Don't use unless /D DebugSystem = 0 for i=1 to sw!0 do switchon CAPS(sw!i) into [ case $D: DebugSystem = deb; endcase case $M: DoMeter= not DoMeter; endcase case $R: pressFileIndex = 0; endcase case $U: UseMicroCode= not UseMicroCode; endcase case $V: Verbose= not Verbose; endcase default: endcase ] // SPruceFile structs for local docs will be stored in Spruce.Queue // To make the right decision about where to put the structs, we // must restore Spoolvec, LocalDocsvec, and pressfileIndex RestoreFromCheckPoint(LEVEternalStatics, LEVEternalStatics) // LocalDocsVec will contain QueueFile page #'s // unless LocalDocsVec do LocalDocsVec = FSGetX(10, SpruceZone, 0) LocalDocsVec = FSGetX(10, SpruceZone, 0) unless SpoolVec do SpoolVec = FSGetX(maxSpooled+1, SpruceZone, 0) //Set up some defaults before processing local switches: let x = vec maxBins; BinCounters = x; Zero(x, maxBins) let pDoc= FSGetX(size DocG/16, SpruceZone, 0) let length = 0 // Zero(pDoc, size DocG/16) PressFile=0 PressServer, spooling, printing = false, false, true // MoveBlock(lv pDoc>>DocG.CreatStr, UserName, size DocG.CreatStr/16) // ------- SpruceInit . . . //local switches: verb-object and noun-object (keyword-value) pairs while ReadParam($P,-1) ne -1 do [ //get the keyword let j=Disambiguate(str); unless j then SpruceCondition(201, ECComTerminate, str) //...and get its value let num=0; if j ls 20 then [ num = ReadParam($D, -1); if num eq -1 then SpruceCondition(202, ECComTerminate) ] switchon j into [ case 1: pDoc>>DocG.nCopies=num; endcase case 2: pDoc>>DocG.UserPageStart=num; //falls through case 3: pDoc>>DocG.UserPageEnd=num; endcase case 4: ResolutionB = num*10; ResolutionS=ResolutionB; endcase case 7: pDoc>>DocG.ScaleOffset=num; endcase case 8: DebugSystem = num; endcase case 20: // Find the PRESS file, create corresponding SpruceFile structure: if ReadParam($P, -1) eq -1 then SpruceCondition(207, ECComTerminate) MoveBlock(lv pDoc>>DocG.FileStr, str, size DocG.FileStr/16) MakeValidSpruceFile(lv pDoc>>DocG.PressFile, str, -1, DISK31) unless pDoc>>DocG.PressFile do SpruceCondition(200, ECComTerminate, str) MoveBlock(lv pDoc>>DocG.CreatStr, UserName, size DocG.CreatStr/16) InitSpruceFile(pDoc>>DocG.PressFile, 1, 3) FillInNames(0, pDoc, pDoc>>DocG.PressFile) ResetSpruceFile(pDoc>>DocG.PressFile) //inc. number of files processed pressFileIndex = pressFileIndex + 1 pDoc>>DocG.PressFile>>SPruceFile.fileCode = pressFileIndex printDoc = pDoc LocalDocsVec!0 = (LocalDocsVec!0) + 1 //inc. length of vector length = LocalDocsVec!0 LocalDocsVec!length = pressFileIndex ActOnEntry(LocalDocsVec!length, false) // get another DocG pDoc = FSGetX(size DocG/16, SpruceZone, 0) endcase case 100: j = j+21 //directive _ 100 case 21: case 22: case 23: PressFile = -1; pDoc>>DocG.printerDirective = j-21; endcase case 24: PressServer, spooling = true, true; endcase case 25: Restart() case 26: xmFonts = true; endcase case 27: case 28: if (printerDevice eq printerPenguin) do [ (lv Capabilities)>>Capabilities.cDuplex = j-27 pDoc>>DocG.duplex = j-27 ]; endcase case 29: case 30: case 31: if (printerDevice eq printerPenguin) do (lv Capabilities)>>Capabilities.cOutputMode = j-29; endcase case 35: j = 36 case 32: case 33: case 34: (lv Capabilities)>>Capabilities.cOverflowProtect = j-32; endcase case 36: case 37: if (printerDevice eq printerPuffin) do (lv Capabilities)>>Capabilities.cBlack = j - 36; endcase ] ] Debug = (DebugSystem() ne 0 if Debug then [ DoFileMeter=true; DoEtherReport=false ] // pDoc>>DocG.PressFile = PressFile // Compute information for image-generation (set nVisibleBands, FA) let nBitsPerScan = MulDiv(ResolutionB, PaperDimensionB, 100) nBitsPerScan=(nBitsPerScan+63)&(-64) // Make multiple of 64 if nBitsPerScan > 4096 then [ SpruceCondition(205, ECContinue) // Warning only -- may be using non-standard nBitsPerScan = 4096 ] // resolution FA = (4096-nBitsPerScan)/16 // Given short scan-lines, some offset in Orbit buffer is reqd. // Following computes number of bands on visible part of page. let nScanLines=MulDiv(ResolutionS, PaperDimensionS, 100) nVisibleBands=(nScanLines+BANDWidth-1)/BANDWidth GetLogoInfo() //sets LogoFont and LogoText statics seed = FSGetX(2, SpruceZone, 0) ReadCalendar(seed) //initialize seed // Save installation statics, as modified, and initialization statics // printDoc=pDoc // save command line document descriptor over junta // temporary -- To save 'new' state of the queuefile, LEVEternalStatics CheckPoint(LEVSharedInitStatics, LEVInitialStatics) CheckPoint(LEVEternalStatics, LEVEternalStatics) //Get rid of the operating system: Junta(levBFSbase, SpruceInitAux) // ~~ consider doing less damage ] // ------------------------------------------------------ and SpruceInitAux() be // ------------------------------------------------------ // Called after Junta -- nothing exists except saved sysDisk, the code, and the OS levels that are // left. The hair at the beginning and end are to recover memory structure and global information after // the junta, and to prepare memory again after releasing the initialization code to free storage. After file // structures are retrieved or whenever free storage is rebuilt, files must be reinitialized (see // SpruceFiles). There are three main jobs here: // First, create a reasonable memory structure, with an adequate display bit map. // Then, save the initialized system on Spruce.Boot via OutLd. Subsequent returns to the spooler from // the Sprint printing system will resume this image. Spruce.Boot is never altered after this // initialization. Spruce determines the difference between the initial state and printer returns by // examining the inMsg, initially cleared (see InLd/OutLd documentation, Sprouller() in Spruce, // SwapSystem() in SpruceUtils (Sprint only)). // Finally, create contexts for the spooler, a user interface, and the Pup package, initialize running // structures, eliminate the initialization code, and call the main Spruce() context-driver routine. [ //Prepare memory for Restore from Checkpoint let PermanentTop=MyFrame()-BASEStackSize // 700 was enough on September 18, 1978 @#335=PermanentTop PermanentBottom=PermanentTop compileif DebugSw then [ Zero(PermanentTop, BASEStackSize-5) ] //Get all the goodies back, this time permanently -- OpenCheckPointFile creates sysDisk! sysDisk = 0; OpenCheckPointFile(0) // restore structure, but file must already exist and be full RestoreFromCheckPoint(LEVSharedInitStatics, LEVInitialStatics) RestoreFromCheckPoint(LEVEternalStatics, LEVEternalStatics) CheckPoint(LEVInitialStatics+1, maxLEV, 1) // clear all operating levels // Create other disk structures, if used drive1Disk = 0; if statusOf31s eq 1 then SetupDrive(DISK31B, SpruceZone) tridentDisk = 0; if tridentUsed then SetupDrive(DISKT80, SpruceZone) // Now have a decent storage zone; restore terminal communications sysZone, @lvSysZone = SpruceZone, SpruceZone dsp = CreateDisplayStream(30, FSGetX(13000), 13000, sysFont) ShowDisplayStream(dsp,DSalone); PutTemplate(dsp,"*N*N") keys = KBDinit(SpruceZone) @#421 = @#421 % #10000 // tie kbd handler to vetical interrupt timeUp = FSGetX(2); ReadCalendar(timeUp) reasonVec = FSGetX(40); reasonVec!0 = 0 inMsg = FSGetX(lInLdMessage+5, SpruceZone, 0) DisableInterrupts() firstDCB = @#420; @#420 = 0 // turn display off // ------------------------------------------------------ let inLd = OutLd(spruceFPRD, inMsg) // won't alter inMsg first time resumeSpruce: // Control returns here from Printer // ------------------------------------------------------ @#420 = firstDCB EnableInterrupts() InitFrameRuntime(true) // use fast GetFrame() and return Which = lv spruceFPRD if inLd ne 0 & (DebugSystemƐ) ne 0 then CallSwat("Spooler: Return from InLd") InitRam(0) // Restart tasks (precaution) // Enter the Context world, initialize main, spooler, user contexts ctxQ = FSGetX(2, SpruceZone, 0) Enqueue(ctxQ, // Spooler runs in main task -- schedule it InitializeContext(FSGetX(MAINStackSize), MAINStackSize, Sprouller)) InitSpool(ctxQ); InitUser(ctxQ) // initialize and enqueue user interface task // let printFile = printDoc>>DocG.PressFile printDoc = 0 numFilesSpooled = 0 unless LocalDocsVec!0 eq 0 % inMsg>>TOSpoolerMsg.completionCode do [ let numToQueue = 1 while numToQueue le LocalDocsVec!0 do [ // should extract fileIndex from LocalDocsVec ActOnEntry(LocalDocsVec!numToQueue, true) //read into core // SpoolVec!0 = (SpoolVec!0) + 1 // let length = SpoolVec!0 // SpoolVec!length = LocalDocsVec!numToQueue Post(printDoc, 0) AddToQueue(printDoc) numFilesSpooled = numFilesSpooled + 1 numToQueue = numToQueue + 1 let printFile = printDoc>>DocG.PressFile // if printFile ne -1 then // [ InitSpruceFile(printFile, 1, 3); FillInNames(0, printDoc, printFile); // ResetSpruceFile(printFile) ] ] ] // save new state of Spoolvec CheckPoint(LEVEternalStatics, LEVEternalStatics) // Throw away initialization code (including this!) let initEnd = OverlayTop OverlayBottom=SpruceInit+1 OverlayTop=OverlayBottom AddToZone(SpruceZone, OverlayTop, initEnd-OverlayTop) Spruce(printDoc) //And run the spooler! ] // ------------------------------------------------------ and Disambiguate(str) = valof // ------------------------------------------------------ // Obtain index for command, if any, that is uniquely specified by substring str. [ let len=str>>STR.length let matchNo=nil let matchCnt=0 for i=1 to 100 do [ let s=selecton i into [ case 1: "Copies" case 2: "Pages" case 3: "To" case 4: "Resolution" case 5: "XOffset" case 6: "YOffset" case 7: "Scale" case 8: "Debug" case 20: "Print" case 21: "Reprint" case 22: "PowerOn" case 23: "PowerOff" case 24: "Server" case 25: "Restart" case 26: "Extended" //use XM, bank 1 for fonts case 27: "OneSided" // penguin option case 28: "TwoSided" // penguin option case 29: "SingleBin" // default for all but Penguin case 30: "MailBox" // penguin option case 31: "MultiBin" // penguin option case 32: "NoProtection" //overflow protection case 33: "JobProtection" //overflow protection case 34: "ContinuousProtection" //overflow protection case 35: "StopAfterJob" //overflow protection case 36: "NoBlack" // Puffin option case 37: "Black" // Puffin option // case 100: "ValidateFonts" //check fonts for landmines that would break Spruce default: 0 ] if s eq 0 % len gr s>>STR.length then loop let match=true for j=1 to len do if ((str>>STR.char^j xor s>>STR.char^j)&(not #40)) ne 0 then match=false if match then [ matchCnt=matchCnt+1 matchNo=i ] ] if matchCnt eq 1 then resultis matchNo resultis false ] // ------------------------------------------------------ and Restart() be // Resume previous Spooler incarnation, assuming no pending files have been completed // ------------------------------------------------------ [ outMsg = FSGetX(lInLdMessage+5, SpruceZone, 0) outMsg>>TOSpoolerMsg.completionCode = CCRestart @#420 = 0; SetRMR(#177776); StartIO(#100000) // Shut display, tasks down DisableInterrupts() InLd(spruceFPRD, outMsg) ] // ------------------------------------------------------ and CAPS(char) = $a le char & char le $z? char-$a+$A, char // upper case only // ------------------------------------------------------ // ------- History . . . // DCS, July 15, 1977 3:52 PM, derived from SpruceInit // July 16, 1977 3:19 PM, add Spooler initialization // July 18, 1977 4:55 PM, Much smaller main stack frame // July 19, 1977 2:39 PM, save and init fonts, displays, keyboards // July 21, 1977 3:38 PM, extend checkpoint levels, implement shared static version // July 22, 1977 4:03 PM, add OutLd // July 29, 1977 3:16 PM, handle stand-alone activities better // August 28, 1977 7:59 AM, Spruce->Sprint, Sprouller->Spruce // October 10, 1977 2:51 PM, add "Version" static, can be set from other programs // October 17, 1977 11:52 AM, move XOffset, Y"" to statics from DocG, version 4.(0,0) // December 20, 1977 12:09 PM, make Trident code work // January 2, 1978 8:42 AM, make it work better // March 3, 1978 7:16 AM, V6.0, OS v14 (new time standard) // August 31, 1978 10:53 AM, allow "Spruce Server Print foo" // September 11, 1978 2:47 PM, revision for new installation, Spruce file creation, checkpointing // September 12, 1978 6:51 AM, increase BASEStackSize // September 18, 1978 10:42 AM, obtain sprintFPRD here if not avail. already // September 18, 1978 3:20 PM, cap switches // September 19, 1978 8:38 AM, format, document // September 22, 1978 9:41 PM, add Restart option // October 16, 1978 9:12 AM, modify buffering for fast files // October 20, 1978 4:30 PM, Enable fast GetFrame, return // March 7, 1979 11:55 AM add global B switch to request 4-color puffin (TEMPORARY!) // May 8, 1979 11:20 AM add ValidateFonts, Extended (set xmFonts) // June 26, 1979 4:21 PM, remove global B switch. Add options to change Capabilities // August 29, 1979 11:37 AM, initialize BinCounters // November 15, 1979 3:17 PM, call GetLogoInfo // January 18, 1980 12:45 PM, 'twosided' sets cDuplex // March 4, 1980 9:41 AM, use static firstDCB to prevent loss of display stream // May 28, 1980, 4:04 PM, os18 lost my kbd interrupt // June 23, 1980, 4:18 PM, make "OneSided" and "TwoSided" set DocG.duplex // September 25, 1982 4:14 PM Modified SpruceInit() to save/restore local // document info. // October 25, 1982 2:08 PM added LEVEternalStatics checkpointing calls. (635)\65b3B440b1B112b13B108b14B155b13B35b24B92b15B21b18B184b28B339b8B266b11B118b47B51b11B249b4B25b25B124b14B1165b79B161b1B255b12B1122b38B112b486B115b3B9b8B12b16B1b23B96b5B1010b20B28b20B46b592B884b2B714b79B70b2B69b72B55b52B1948b63B1632b2B44b39B10b14B49b280B5b8B5b2B21b117B24b2B75b2B32b4B3b45v14V5v15V1B1397b2B