// SpruceInstall.Bcpl -- Spruce Spooler Installation // errors 250 // get "Spruce.d" was too big: only need get "SprucePrinters.d" get "Sprucedoc.d" get "spruceMisc.d" get "SpruceFiles.d" get "MenuDefs.d" get "SpruceParamsNames.d" get "SpruceFilesNames.d" external // defined here [ SpruceInstall MenuInitHelp ] external // external [ // ******* Functions between SpruceSpool and SpruceInUtil not needed during installation // ******* (SomeoneIsKnocking to ValidateSpruceFile) // ******* Load command file must be maintained to retain this fact SomeoneIsKnocking ValidateSpruceFile // ******* // SpruceFiles ForgetSpruceFile InitSpruceFile ResetSpruceFile // SpruceInUtil DiskObject GetPrinterNames MakeValidSpruceFile SetupDrive StatusOf31s // SpruceCheck CheckPoint LevelPos OpenCheckPointFile RestoreFromCheckPoint // Menu Package // CreateMenuDisplayStream // FillBox // GetString // MenuSize // ScanMenu // WriteBox // Loaded Menus MenuFilesHelp MenuParamsHelp // Spruce Utils CreateFPRD FSGetX FSInit FSPut InitRam LoadRam SpruceError // Template PutTemplate // TFS TFSClose TFSInit // BFS BFSClose // OS MyFrame ShowDisplayStream Zero // statics BandFile BitMarginAdjust breakPage Capabilities CheckPrAttr DebugSystem DutyCycle drive1Disk ErrorFile Facets FontFile LandscapeDevice maxQueued menu menuBuf allocLogFile // MenuData menuStream NumBins OverlayTop PaperDimensionB PaperDimensionS PaperSpeedInches PermanentBottom PolygonRatio printerDevice printerForward printerName PRamImage ResolutionB ResolutionS ScanLengthInches ScanMarginAdjust SpoolFile sprintFPRD spruceFPRD SpruceZone tridentDisk tridentUsed statusOf31s UserName // **** See SpruceStatics, SpruceUtils, below -- more memory for installation MoreLow; MoreHigh ] static InstallStackSize = 2000 static [ menu; menuStream; menuBuf; MenuInitHelp=0; ChangeRoutine ] static [ errorSpecs; fontSpecs; spoolSpecs; bandSpecs; okToInstall ] structure SPECS: [ fileId word; devId word; defDev word; sizeId word; defSize word ] // Installation is a menu-driven process, using the menu package contained in Menu.dm (K. Knox, proprietor.) // The companion MenuEdit program, run on a different disk, creates and maintains the following files, // which are part of the standard Spruce source package: // SpruceNames.d, SpruceTables.bcpl -- describe both menus (see below) // SpruceParamsNames.d, SpruceParamsTables.bcpl -- describe the params menu (see below) // SpruceFilesNames.d, SpruceNamesTables.bcpl -- describe the file config. menu. // Installation involves setting a number of printing and spooling parameters, and describing the sizes and locations // of files used in the spooling and printing process. The Spruce operations manual contains pictures of the parameters and // configuration menus, along with descriptions of their use. It would have been better if both menus were simultaneously // available, but space considerations intruded. The menus are created by running MenuEdit to modify the Spruce // (complete) menu, then by extracting them into the SpruceParams and SpruceFiles menus. If space later allows, // they can be remerged. The menus are presented to the user sequentially, Params first. // Each menu, and its underlying installation variables, are initialized from some standard defaults. // Then values produced during previous installation sessions are obtained from the checkpoint file, if it // exists and is valid. These are reflected in the menus, then the user is given the opportunity to change // them, accept the current set, or quit without affecting the installation. The configuration cannot be // accepted ("Install" operation) unless all required files are allocated. Installation involves storing the // new values back into the checkpoint file. // The hair in the Change functions is due to the desire to use them both to reflect current values // derived from checkpoint information or due to changes in other values (e.g., printer choice affects paper // size and orientation, looking up a pre-existing file causes changes in display of size and disk // location), and to use them to respond to keyboard input. // ------------------------------------------------------ let SpruceInstall(doInstall, runCfa) be // ------------------------------------------------------ // After loading the RAM, eliminating its storage, and setting up memory structure variables, // create, intialize, and/or validate the Checkpoint file, as necessary. If the checkpoint file seemed // invalid, too old for the current version (see version management in SharedStatics and in // OpenCheckPointFile()), or had not existed, proceed with the installation process. Proceed also, if // doInstall was true. Otherwise, return and continue with initialization. // Installation proceeds for each of the menus, as described in the general comments. The Change() // function, conditioned by InitMenu, simply invokes the appropriate Change...() function for the list // supplied to it. Keybord input is obtained using the menu package function ScanMenu(). // Once installation is complete, Spruce finishes. ~~ Consider returning as usual to run Spruce as // requested in the command line. [ InitRam(PRamImage, OrbitRMR) OverlayTop=LoadRam //Bottom of free storage for FSInit let PermanentTop = MyFrame()-InstallStackSize @#335 = PermanentTop; PermanentBottom = PermanentTop statusOf31s = StatusOf31s() // (if allowed&necc.), create and init. file -- if had to init, install independent of request let OpCpResult = OpenCheckPointFile(runCfa) MakeValidSpruceFile(lv allocLogFile, "Spruce.Alloc", 30, DISK31) InitSpruceFile(allocLogFile, 4, 3) ResetSpruceFile(allocLogFile) // let s = OpenFileFromFp(allocLogFile>>SPruceFile.map>>FM.fp) if OpCpResult & not doInstall return let pNameTab = table[ 0; 0; 0; 0; 0 ] let pNameVec = vec 19 for i= 0 to 4 do pNameTab!i = pNameVec + i*4 GetPrinterNames(pNameTab) // Initialize Menu menuStream, menuBuf = 0, 0 // ****** see discussion about unused code above -- give some space back MoreLow, MoreHigh = SomeoneIsKnocking, ValidateSpruceFile-5 // ***** InitMenu(MenuParamsHelp, ChangeParam) // Calls FSInit, allocates menus Select(hd1) for i = 0 to maxPrinterDevice do [ PutBoxTemplate(ptDover + i, "$S", pNameTab!i) ] // Set default installation values ~~ should obtain from device type -- no access, for now printerDevice = printerDover // Now, set up a table of default printer attributes for each type of printer let defaultTab = FSGetX((maxPrinterDevice+1)*lenPrAttr) let p = defaultTab CheckPrAttr = defaultTab // may be overwritten by RestoreFromCheckpoint below for i = 0 to maxPrinterDevice do [ p>>PrinterAttributes.Capabilities = (table[ DoverDefault; PenguinDefault; SequoiaDefault; PimlicoDefault; PuffinDefault ])!i p>>PrinterAttributes.PaperDimensionB = (table[ 106; 106; 106; 85; 85 ])!i p>>PrinterAttributes.PaperDimensionS = (table[ 85; 85; 85; 110; 110 ])!i p>>PrinterAttributes.PaperSpeedInches = (table[ 1020; 1100; 340; 400; 400 ])!i p>>PrinterAttributes.ScanLengthInches = (table[ 117; 121; 112; 95; 118 ])!i p>>PrinterAttributes.LandscapeDevice = (table[ -1; -1; -1; 0; 0 ])!i p>>PrinterAttributes.printerForward = (table[ 0; 0; 0; -1; -1 ])!i p>>PrinterAttributes.breakPage = (table[ -1; -1; -1; -1; -1 ])!i p>>PrinterAttributes.BitMarginAdjust = (table[ 120; 220; 101; 102; 630 ])!i p>>PrinterAttributes.ScanMarginAdjust = (table[ 190; 1730; 104; 105; 528 ])!i p>>PrinterAttributes.DutyCycle = (table[ 90; 98; 90; 87; 99 ])!i p>>PrinterAttributes.Facets = (table[ 32; 22; 36; 12; 22 ])!i p>>PrinterAttributes.PolygonRatio = (table[ 24; 24; 24; 24; 24 ])!i p>>PrinterAttributes.NumBins = (table[ 1; 21; 1; 1; 1 ])!i p = p + lenPrAttr ] SetPrinterParms() //moves printerDevice set into statics ResolutionB, ResolutionS = 3840, 3840 printerName = UserName DebugSystem = #40 // if /D, don't actually run Orbit RestoreFromCheckPoint(LEVSharedInstStatics, LEVInstallationStatics, 0, true) let dev = selecton printerDevice into [ default: 0 case printerDover: ptDover; case printerPenguin: ptPenguin; case printerSequoia: ptSequoia case printerPimlico: ptPimlico; case printerPuffin: ptPuffin ] ChangeParam(dev) Change(table [ psS; psB; rS; rB; maS; maB; llS; ps; pn; dbg; pm; fp; bp; 0 ] ) // Main parameter installation loop while ChangeParam(ScanMenu(menu), true) loop // may finish instead of returning SavePrinterParms() //moves last changes into table for printerDevice CheckPoint(LEVSharedInstStatics, LEVInstallationStatics) FSPut(defaultTab) // File Configurations InitMenu(MenuFilesHelp, ChangeConfig) RestoreFromCheckPoint(LEVSharedInstStatics, LEVInstallationStatics, 0, true) Select(hd2) let v = table [ fnErrors; fdErrors; DISK31; fsErrors; -1 ]; errorSpecs = v let v = table [ fnFonts; fdFonts; -1; fsFonts; -1 ]; fontSpecs = v let v = table [ fnSpool; fdSpool; -1; fsSpool; -1 ]; spoolSpecs = v let v = table [ fnBands; fdBands; -1; fsBands; -1 ]; bandSpecs = v Change(table [ dcM31; dcT80; #402; 0 ]) okToInstall = 1; OKToInstall() while ChangeConfig(ScanMenu(menu), true) loop // may finish instead of returning spruceFPRD = CreateFPRD("Spruce.Boot", true) // Compute FPRDs (InLd, OutLd arguments) for self and Spruce printer unless spruceFPRD do SpruceError(257) // Compute maxQueued from LEVRunDocs checkpoint capacity let checkSize = LevelPos(0, LEVRunDocs, true) - LevelPos(0, LEVRunDocs) let entrySize = 2*LenCHecord + lenDocG + lenSPruceFile maxQueued = checkSize/entrySize maxQueued = maxQueued - (maxQueued rshift 3) // 7/8, for safety // Any other state to be initialized goes here..... CheckPoint(LEVSharedInstStatics, LEVInstallationStatics) finish ] // ------------------------------------------------------ and ChangeParam(boxId, readFromKeyboard; numargs na) = valof // ------------------------------------------------------ // Installation of parameters, based on Params menu. Companion to ChangeConfig, below. // readFromKeyboard, if true, identifies the boxId (menu box index) as the independent variable in // the change process; dependent values will be changed via recursive calls with readFromKeyboard false. // readFromKeyboard also requests, for numerical and string boxes, that the new values be read using GetParamArg(). // Consult SpruceParamsNames.d and the picture, via MenuEdit, for the meanings of case indices. // Consult the menu package for menu-related functions not found in the utilities at the end of this module. // When the printer selection is changed, a set of system-provided defaults fills a number of related // boxes. ~~ Consider remembering the previously-installed values for each printer type. // Two menu items are commands: "Quit" (return to exec) and "Install Files" (go on to next menu.) [ if na<2 then readFromKeyboard = false let statAdr, name, specs = nil, nil, nil switchon boxId into [ // Printer Type: case ptDover: case ptPimlico: case ptSequoia: case ptPuffin: case ptPenguin: [ compileif ptPenguin-ptDover ne 4 then [ MenuAllocationError() ] for i = ptDover to ptPenguin do Select(i); Deselect(boxId) if readFromKeyboard do SavePrinterParms() //save old values let devIndex = boxId-ptDover // Penguin acts like Dover, for now let devTab = table [ printerDover; printerPimlico; printerSequoia; printerPuffin; printerPenguin ] printerDevice = devTab!devIndex SetPrinterParms() // move in attributes for new device Change(table[ psB; psS; maS; maB; llS; ps; pm; fp; bp; 0 ]) endcase ] // Printing Parameters case psB: case psS: case rB: case rS: case llS: case maS: case maB: case ps: case dbg: case pn: GetParamArg(boxId, readFromKeyboard); endcase // Printing Options: case pm: LandscapeDevice = LandscapeDevice xor readFromKeyboard PutBoxTemplate(boxId, "$S", LandscapeDevice? "Landscape", "Portrait"); endcase case fp: printerForward = printerForward xor readFromKeyboard PutBoxTemplate(boxId, "$S Page First", printerForward? "First", "Last"); endcase case bp: breakPage = breakPage xor readFromKeyboard PutBoxTemplate(boxId, "$SBreak Page", breakPage? "", "No "); endcase // Commands: case cParamQuit: InitMenu(0); finish case cParamInstall: resultis false // go on default: if boxId then Deselect(boxId) // ignore ] resultis true // go on ] // ------------------------------------------------------ and GetParamArg(boxId, readFromKeyboard) be // ------------------------------------------------------ // Use routines from utilities below and from menu package to obtain (if readFromKeyboard) and // correctly display choices for numerical or string boxes. [ let str = readFromKeyboard? GetString(Box(boxId), 0, SpruceZone), 0 let statAdr, places, isOct, specs = nil, 0, false, nil switchon boxId into [ // numbers: case psB: statAdr = lv PaperDimensionB; docase #401 // *10 case psS: statAdr = lv PaperDimensionS; docase #401 case rB: statAdr = lv ResolutionB; docase #401 case rS: statAdr = lv ResolutionS; docase #401 case llS: statAdr = lv ScanLengthInches; docase #401 case ps: statAdr = lv PaperSpeedInches; docase #402 // *100 case dbg: statAdr = lv DebugSystem; isOct = true; docase #400 // *1 case maS: statAdr = lv ScanMarginAdjust; docase #400 case maB: statAdr = lv BitMarginAdjust; docase #400 case #402: places = 1 case #401: places = places+1 case #400: if readFromKeyboard then @statAdr = GetNumber(str, places) unless @statAdr do @statAdr = 1 // prevent some ridiculous stuff PutNumber(boxId, @statAdr, places, isOct) endcase // Strings case pn: if readFromKeyboard then [ printerName = str; str = 0 ] PutBoxTemplate(pn, "$S", printerName); endcase default: SpruceError(259) ] if str then FSPut(str) ] // ------------------------------------------------------ and ChangeConfig(boxId, readFromKeyboard; numargs na) = valof // ------------------------------------------------------ // Installation of file configurations, based on Configs menu. Companion to ChangeParam, below. // Activities similar to ChangeParam, above. The numerical collecting is self-contained in the fs... cases // (number of pages specs.) Most of the hair is due to the provisions for defaulting device and page size // selections to the values obtaining when last the files were installed, and for falling back into legal // default configurations when the range of options is reduced by eliminating one or more auxiliary // disks from consideration. The "specs" tables are set up with values promoting the use of these // defaults when installation begin, and are updated to reflect the actual values, obtained from the files // themselves or from the keyboard, as the process progresses. ~~ Consider attaching the specs tables // to the menu items, eliminating many repetitive setup operations. // Two menu items are commands: "Quit" -- return to exec, and "Install" -- save newly selected // installation values and quit. "Install" is not displayed, and its selection is not obeyed, unless the // current configuration is correct and complete. [ if na<2 then readFromKeyboard = false let statAdr, name, specs = nil, nil, nil switchon boxId into [ // Disk Configurations: case dcM31: if statusOf31s eq 2 then [ Select(boxId); endcase ] // ignore if readFromKeyboard then statusOf31s = statusOf31s xor 1 // 0 or 1 test statusOf31s&SetupDrive(DISK31B, SpruceZone, true) then Deselect(boxId) // accept or [ if drive1Disk then BFSClose(drive1Disk);Select(boxId);drive1Disk,statusOf31s=0,0 ] test readFromKeyboard then docase #402 or endcase // adjust files appropriately case dcT80: compiletest TridentSw ifnot [ docase #401 ] ifso [ tridentUsed = tridentUsed xor readFromKeyboard if tridentUsed¬ tridentDisk then tridentDisk = SetupDrive(DISKT80, SpruceZone, true) test tridentUsed&tridentDisk then Deselect(boxId) or [ if tridentDisk then TFSClose(tridentDisk) tridentUsed, tridentDisk = false, 0; Select(boxId) ] test readFromKeyboard then docase #402 or endcase ] case #402: Change(table [ fnFonts; fnErrors; fnSpool; fnBands; 0 ]); endcase // File Validations and Specifications case fnErrors: statAdr, name, specs = lv ErrorFile, "Spruce.Errors", errorSpecs; docase #407 case fnFonts: statAdr, name, specs = lv FontFile, "Spruce.Fonts", fontSpecs case #407: [ unless readFromKeyboard¬ IsSelected(boxId) do docase #403 Select(boxId); endcase ] case fnSpool: statAdr, name, specs = lv SpoolFile, "Spruce.Spool", spoolSpecs; docase #403 case fnBands: statAdr, name, specs = lv BandFile, "Spruce.Bands", bandSpecs; docase #403 case #403: [ let dev, pgs = specs>>SPECS.defDev, specs>>SPECS.defSize unless DiskObject(dev) do dev, pgs = -1, -1 if readFromKeyboard&IsSelected(boxId) then [ if @statAdr then ForgetSpruceFile(@statAdr); @statAdr = 0 if dev eq -1 then dev = DISK31 ] MakeValidSpruceFile(statAdr, name, pgs, dev) test @statAdr ifnot specs>>SPECS.defSize = -1 ifso [ specs>>SPECS.defSize = statAdr=>SPruceFile.numPages specs>>SPECS.defDev = statAdr=>SPruceFile.deviceCode ] ChangeConfig(specs>>SPECS.devId); ChangeConfig(specs>>SPECS.sizeId) (@statAdr? Deselect, Select)(boxId) endcase ] // ------- ChangeConfig . . . case fsErrors: specs, statAdr = errorSpecs, lv ErrorFile; docase #410 case fsSpool: specs, statAdr = spoolSpecs, lv SpoolFile; docase #410 case fsBands: specs, statAdr = bandSpecs, lv BandFile; docase #410 case fsFonts: specs, statAdr = fontSpecs, lv FontFile; docase #410 // never from kbd case #410: [ let str = readFromKeyboard? GetString(Box(boxId), 0, SpruceZone), 0 let places, isOct = 0, false let curSize = specs>>SPECS.defSize if readFromKeyboard then [ Select(specs>>SPECS.fileId); curSize = GetNumber(str, 0) ] // invalidate specs>>SPECS.defSize = curSize test curSize ne -1 then PutNumber(boxId, curSize, 0, false) or FillBox(Box(boxId), white) if str then FSPut(str) endcase ] case fdErrors: specs, statAdr = errorSpecs, lv ErrorFile; docase #404 case fdFonts: specs, statAdr = fontSpecs, lv FontFile; docase #404 case fdSpool: specs, statAdr = spoolSpecs, lv SpoolFile; docase #404 case fdBands: specs, statAdr = bandSpecs, lv BandFile; docase #404 case #404: [ let CycleDisk(ch) = selecton ch into [ case DISK31: DISK31B; case DISK31B: DISKT80; default: DISK31 ] let curChoice = specs>>SPECS.defDev let nextChoice = readFromKeyboard? CycleDisk(curChoice), curChoice until DiskObject(nextChoice) do nextChoice = CycleDisk(nextChoice) specs>>SPECS.defDev = nextChoice PutBoxTemplate(boxId, "$S", selecton nextChoice into [ case DISK31: "DP0"; case DISK31B: "DP1"; case DISKT80: "Trident" ]) let fileId = specs>>SPECS.fileId if readFromKeyboard&nextChoice ne curChoice then [ specs>>SPECS.defSize = -1; Select(fileId); ChangeConfig(fileId) ] endcase ] // commands: case cConfigInstall: test OKToInstall() docase #420 or docase #401 // ignore case cConfigQuit: okToInstall = false case #420: InitMenu(0); compileif TridentSw then [ if tridentUsed then TFSClose(tridentDisk) ] if drive1Disk then BFSClose(drive1Disk) test okToInstall resultis false or finish default: if boxId then Deselect(boxId) // ignore ] if readFromKeyboard then OKToInstall() resultis true // go on ] // ------------------------------------------------------ and OKToInstall() = valof // ------------------------------------------------------ // Called when state of any file has changed. Determines if all requisite files exist and have legal // SpruceFile structures. Adjusts the state of the "INSTALL" menu command based on the result. [ let files = table [ fnErrors; fnFonts; fnSpool; fnBands; 0 ] let file = nil let res = valof [ for i = 1 to 99 do test valof [ file = files!i; resultis file ] ifnot break ifso [ if IsSelected(file) resultis false ] resultis true ] if res ne okToInstall then PutBoxTemplate(cConfigInstall, "$S", res? "INSTALL", "") okToInstall = res resultis res ] // ------------------ Installation Utilities ----------------- // ------------------------------------------------------ and InitMenu(helpRoutine, changeRoutine) be // ------------------------------------------------------ // helpRoutine() is one or the other of the MenuInitHelp routines created by the menu package; they // have been manually edited to have different names so that both menus can be simultaneously loaded. // changeRoutine() is one of the two above. Delete any previous menu and its buffer space, create the // new one, set up the changeRoutine() for use by the Change() function. Release any previous menu's // menu description to SpruceZone [ if menuStream then ShowDisplayStream(menuStream, DSdelete) if MenuInitHelp then OverlayTop = MenuInitHelp FSInit() MenuData, MenuInitHelp = 0, 0; unless helpRoutine return; MenuInitHelp = helpRoutine let lenMenu = MenuSize()+1 //looks like CreateMenuDisplayStream is going to even word align it menuBuf = FSGetX(lenMenu) menuStream = CreateMenuDisplayStream(menuBuf, lenMenu) menu = MenuData>>DATA.menu ShowDisplayStream(menuStream) ChangeRoutine = changeRoutine ] // ------------------------------------------------------ and Change(params) be // ------------------------------------------------------ // ChangeRoutine is selected from {ChangeParam(), ChangeConfig()} by InitMenu() call. // Execute the selected routine for all boxIds (menu box indices) in a nil-terminated vector. for i = 0 to 999 do [ let param = params!i; unless param break; ChangeRoutine(param) ] // ------------------------------------------------------ and GetNumber(str, places) = valof // ------------------------------------------------------ // Returns the numerical value of the string, changing to octal if any of a number of optional syntax // triggers is present. Places indicates the location of the (decimal) fixed point for the number. The // number is returned and stored as "number*10^places". ~~ Consider using EvalParam? [ let dec, oct, char, wasDot, isDec = 0, 0, nil, false, true for i = 1 to str>>STR.length do switchon valof [ char = str>>STR.char^i; resultis char ] into [ case $#: isDec = false; endcase case $0 to $7: if places<0 loop; oct = oct lshift 3 + (char-$0) case $8 to $9: if places<0 loop; dec = dec*10+(char-$0) if wasDot then places = places-1; endcase case $.: wasDot = true; places = places-1; endcase case $B: case $b: case $Q: isDec = false; endcase default: loop // take anything! ] unless wasDot do places = places-1 unless isDec do dec = oct for i = 0 to places do dec=dec*10 resultis dec ] // ------------------------------------------------------ and PutNumber(boxId, value, places, isOct) be // ------------------------------------------------------ // Writes value as sole occupant of specified box, with places places, considered octal if isOct. [ let fract = 0; places = selecton places into [ case 0: 1; case 1: 10; case 2: 100 ] fract = value rem places; value = value/places PutBoxTemplate(boxId, (isOct? "#$UO", not fract? "$D", places eq 100? "$D.$2F0D", "$D.$D"), value, fract) ] // ------------------ Installation Utilities (menu-specific) . . . // ------------------------------------------------------ and IsSelected(boxId) = (Box(boxId))>>BOX.selected ne 0 // Is box selected? (see below) // ------------------------------------------------------ // ------------------------------------------------------ and Select(boxId) be // ------------------------------------------------------ // Force box to be selected (see menu documentation for definition) [ if IsSelected(boxId) return let box = Box(boxId) box>>BOX.selected = true FillBox(box, 0) ] // ------------------------------------------------------ and Deselect(boxId) be // ------------------------------------------------------ // Force box to be deselected [ unless IsSelected(boxId) return let box = Box(boxId) box>>BOX.selected = false FillBox(box, 0) ] // ------------------------------------------------------ and PutBoxTemplate(boxId, str, a, b, c, d, e, f, g) be // ------------------------------------------------------ // Using a simple string stream, use PutTemplate to construct a box's contents [ let P(s, c) be [ let st = s>>ST.par1; let ln = st>>STR.length+1; st>>STR.length = ln; st>>STR.char^ln = c ] Deselect(boxId) let box = Box(boxId) FillBox(box, white) let v = vec 20 v!0 = 0 let s = vec 10; Zero(s, 10); s>>ST.puts = P; s>>ST.par1 = v PutTemplate(s, str, a, b, c, d, e, f, g) if v>>STR.length then WriteBox(box, v) ] // ------------------------------------------------------ and Box(boxId) = menu>>MENU.box^boxId // see menu pkg. Return box corresponding to boxId // ------------------------------------------------------ //these probably belong in SpruceinUtils // ------------------------------------------------------ and SetPrinterParms() be // ------------------------------------------------------ [ let v = CheckPrAttr let p = printerDevice v = v + p*lenPrAttr Capabilities = v>>PrinterAttributes.Capabilities PaperDimensionB = v>>PrinterAttributes.PaperDimensionB PaperDimensionS = v>>PrinterAttributes.PaperDimensionS PaperSpeedInches = v>>PrinterAttributes.PaperSpeedInches ScanLengthInches = v>>PrinterAttributes.ScanLengthInches LandscapeDevice = v>>PrinterAttributes.LandscapeDevice printerForward = v>>PrinterAttributes.printerForward breakPage = v>>PrinterAttributes.breakPage BitMarginAdjust = v>>PrinterAttributes.BitMarginAdjust ScanMarginAdjust = v>>PrinterAttributes.ScanMarginAdjust DutyCycle = v>>PrinterAttributes.DutyCycle Facets = v>>PrinterAttributes.Facets PolygonRatio = v>>PrinterAttributes.PolygonRatio NumBins = v>>PrinterAttributes.NumBins ] // ------------------------------------------------------ and SavePrinterParms() be // ------------------------------------------------------ [ let v = CheckPrAttr let p = printerDevice v = v + p*lenPrAttr v>>PrinterAttributes.Capabilities = Capabilities v>>PrinterAttributes.PaperDimensionB = PaperDimensionB v>>PrinterAttributes.PaperDimensionS = PaperDimensionS v>>PrinterAttributes.PaperSpeedInches = PaperSpeedInches v>>PrinterAttributes.ScanLengthInches = ScanLengthInches v>>PrinterAttributes.LandscapeDevice = LandscapeDevice v>>PrinterAttributes.printerForward = printerForward v>>PrinterAttributes.breakPage = breakPage v>>PrinterAttributes.BitMarginAdjust = BitMarginAdjust v>>PrinterAttributes.ScanMarginAdjust = ScanMarginAdjust v>>PrinterAttributes.DutyCycle = DutyCycle v>>PrinterAttributes.Facets = Facets v>>PrinterAttributes.PolygonRatio = PolygonRatio v>>PrinterAttributes.NumBins = NumBins ] // ------- History . . . // DCS, September 6, 1978 4:59 PM, derived from non-display version // September 7, 1978 9:24 PM, more // September 7, 1978 10:07 PM, syntax errors // September 8, 1978 2:58 PM, repair number get, octal display // September 9, 1978 2:30 PM, add file stuff // September 11, 1978 10:49 AM, split menus (sob) for space reasons, fix string input bug // September 12, 1978 6:53 AM, repair lingering problems // September 14, 1978 12:25 PM, allow SPruceFiles to use their default devices // September 18, 1978 10:29 AM, change in FPRD installation // September 19, 1978 1:24 PM, format, document // September 21, 1978 3:45 PM, contribute menu spec to storage after use. // October 17, 1978 2:55 PM, turn puffin on. BWB // October 19, 1978 10:57 AM, contribute unused runtime code to storage, right away // November 10, 1978 10:31 AM, increase installation stack size // first cut with PrinterAttribute stuff // March 7, 1979 11:41 AM correct puffin install values, fix PutNumber, crude validity check // fix ~~.d names // May 9, 1979 4:02 PM bump menusize by one to allow for even word alignment // July 1, 1979 3:21 PM, set default printer capabilities // August 29, 1979 10:52 AM, add NumBins to printer attribute stuff // September 25, 1979 2:53 PM, get printer device names from User.Cm // January 30, 1980 1:52 PM, Load orbit controlling microcode // (635)\649b33B728b14B4231b245B7b10B3862b10B