// SpruceFilesInit.Bcpl // Errors 2000 get "SpruceFiles.d" get "isf.d" external // Internal [ CreateSpruceFile ForgetSpruceFile CreateSpruceSubfile InitSpruceSubfile ] external [ // from OS DefaultArgs; MoveBlock // from ISF InitFmap; IndexedPageIO // From Spruce Utilities Max; Min; PageToPos // From SpruceFiles DiskObject; InitSpruceFile; ResetSpruceFile // From Other Spruce Sources SpruceError; FSGetX; FSPut; SpruceZone // From SpruceFilesMl VpageToRpage // virtual to real ] // ------------------------------------------------------ let CreateSpruceFile(fP, numPages, zone, deviceCode, baseZone; numargs na) = valof // ------------------------------------------------------ // The SpruceFiles functions neither create nor allocates pages for files (although ISF is capable of // the latter.) Nor do they manipulate the name directory. CreateSpruceFile will validate a file's length (if // numPages ne -1) and build the ISF map for it. It returns an intialized SPruceFile structure, with the // map embedded. The returned file is "invalid", in that an InitSpruceFile(..) must be performed before use // Return 0 if fP is invalid, the map cannot be built, or the file is the wrong length (~~ Consider // a way to report the nature of the problem.) . zone is used for temporary // allocations, and baseZone (defaults to zone) for the permanent SPruceFile and map allocation. deviceCode // is DISK31, DISK31B, or DISKT80. Only fP is mandatory; the others default as described below. [ DefaultArgs(lv na, -1, -1, SpruceZone, DISK31, 0) unless baseZone do baseZone = zone let checkPages = numPages // Create map, verify file's existence, size let map = FSGetX(maxFmapLen, zone) // big enough for biggest reasonable map, compressed below let extendSize = Min(48, numPages) unless InitFmap(map,maxFmapLen,fP,false,extendSize,zone,DiskObject(deviceCode), lv numPages) do resultis 0 // check error if checkPages ne -1 & numPages ne checkPages resultis 0 // # pages doesn't match // Create file structure let sF = FSGetX(lenSPruceFile, baseZone, 0) sF>>SPruceFile.numPages = numPages sF>>SPruceFile.maxPages = numPages sF>>SPruceFile.deviceCode = deviceCode sF>>SPruceFile.map = map InitSpruceFile(sF, 0, 0, zone); ResetSpruceFile(sF) // leaves invalid let sP = nil // extend file, set up map -- do not let it get too long let evenExtend = (numPages/extendSize)*extendSize let buffer = FSGetX(minLenSPrucePage+sF>>SPruceFile.pageSize, zone) let numChars = IndexedPageIO(map, evenExtend, buffer, 1, isfRead) unless evenExtend eq numPages do [ map>>FM.extend = numPages-evenExtend // creep out to end numChars = IndexedPageIO(map, numPages, buffer, 1, isfRead) ] sF>>SPruceFile.numChars = numChars FSPut(buffer, zone) // compress map to baseZone let lenMap = map>>FM.last+6 map>>FM.end = lenMap let newMap = FSGetX(lenMap, baseZone) MoveBlock(newMap, map, lenMap) FSPut(map, zone) sF>>SPruceFile.map = newMap resultis sF ] // ------------------------------------------------------ and ForgetSpruceFile(spruceFile) be // ------------------------------------------------------ // Free the structure's storage. Illegal if file allocated from checkpoint zone. [ let zone = spruceFile>>SPruceFile.zone ResetSpruceFile(spruceFile) unless zone do zone = SpruceZone // ~~ This is probably a kludge if zone ne 0 then //file must be initialized! [ let map = spruceFile>>SPruceFile.map unless spruceFile>>SPruceFile.isSubFile do FSPut(map,zone) ] FSPut(spruceFile,zone) ] // ------------------------------------------------------ and CreateSpruceSubfile(lvSpruceFile, firstPage, numPages, numChars, zone; numargs na) = valof // ------------------------------------------------------ // A subfile is a contiguous region of a SPruceFile, which behaves to its clients in most ways like // a standard SPruceFile. It may not exceed the parent (superFile) file in length, but it can "wrap // around": if page n is superFile's page max, page n+1 is superFile's page 1. It can also be mapped // in reverse page order into superFile: page 1 to superFile's page x, page 2 to page x-1, ... page m to // page 1, page m+1 to page max, etc. // The functions VpageToRpage and RpageToVpage (SpruceUtils and SpruceMl) produce mappings // from subfile to superfile and the inverse. If the lvSpruceFile static pointer indicates another subfile, // its parent is used, with adjusted firstPage, so nesting is never more than one deep. // The superFile's structure must be resident whenever the subfile structure is used. [ let spruceFile = @lvSpruceFile if spruceFile>>SPruceFile.isSubFile then // never more than one deep! [ // create subfile of specified file's parent -- guaranteed not to be subfile firstPage = VpageToRpage(spruceFile, firstPage) lvSpruceFile, spruceFile = spruceFile>>SPruceFile.lvSuperFile, @lvSpruceFile ] DefaultArgs(lv na, -3, #77777, spruceFile>>SPruceFile.zone) let sF = FSGetX(lenSPruceFile, zone, 0) let map = spruceFile>>SPruceFile.map sF>>SPruceFile.map = map sF>>SPruceFile.lvSuperFile = lvSpruceFile sF>>SPruceFile.deviceCode = spruceFile>>SPruceFile.deviceCode InitSpruceFile(sF, 0, 0, zone); ResetSpruceFile(sF) // fill in some more of the blanks InitSpruceSubfile(sF, firstPage, numPages, numChars) resultis sF ] // ------------------------------------------------------ and InitSpruceSubfile(sF, firstPage, numPages, numChars; numargs na) be // ------------------------------------------------------ // Allows reassignment of mapping from existing subfile to parent file locations. [ // numPages<0 means file is to be arranged in reverse page order if na<4 then numChars = #77777 let isBackwards = false sF>>SPruceFile.backwards = false if numPages<0 then [ isBackwards = true; numPages = 0 - numPages ] let superFile = @sF>>SPruceFile.lvSuperFile unless sF>>SPruceFile.lvSuperFile & superFile do SpruceError(2080, sF) let maxPages = superFile>>SPruceFile.maxPages sF>>SPruceFile.maxPages = maxPages unless 1 le firstPage & firstPage le maxPages & numPages le maxPages do SpruceError(2020) sF>>SPruceFile.offSet = firstPage-1 sF>>SPruceFile.numPages = numPages let realLastPage = VpageToRpage(sF, numPages) let cPP = sF>>SPruceFile.pageSize lshift 1 let lpChars = superFile>>SPruceFile.numChars if realLastPage < firstPage & lpChars ne cPP then SpruceError(2070, superFile) // too hard to wrap around if realLastPage eq maxPages & isBackwards & lpChars ne cPP then SpruceError(2090, superFile) // backwards cannot start here sF>>SPruceFile.backwards = isBackwards sF>>SPruceFile.numChars = Min(numChars, (realLastPage ne maxPages? cPP, superFile>>SPruceFile.numChars)) ] // ------- History . . . // DCS, March 10, 1978 8:49 AM, extracted from SpruceFiles // September 3, 1978 6:44 PM, superFile -> lvSuperFile, allow subfile as arg to Create...Subfile // (meaning: create another subfile of subfile arg's parent.) // September 12, 1978 3:49 PM, add CreateSpruceFileCfa // September 12, 1978 10:51 PM, compress map to baseZone after creation // September 14, 1978 10:48 AM, CreateSpruceFile... returns 0 if no such file // September 18, 1978 8:48 AM, numPages to CreateSpruceFile is -1 for "don't check", else just // a value to be checked against actual current file length -- Create.. fails if doesn't check. // Map extends faster, requires file to be full length already. // September 19, 1978 6:42 PM, formatting, documentation // October 16, 1978 8:25 AM, modifications for fast files // (635)\1689b10B124b10B1546b53B100b4B