DIRECTORY Atom, Basics, BTree, BTreeSimple, Commander, CommandToolExtras, FS, IO, Log, NamesExtras, PrincOps, ProcessProps, RefTab, RefText, Rope, LogDB, UserProfile; LogDBImpl: PROGRAM IMPORTS Atom, Basics, BTree, BTreeSimple, Commander, CommandToolExtras, FS, IO, Log, NamesExtras, RefTab, ProcessProps, RefText, Rope, UserProfile EXPORTS LogDB SHARES Rope = BEGIN OPEN IO; ROPE: TYPE = Rope.ROPE; Attrs: TYPE = LogDB.Attrs; WPListing: TYPE = LogDB.WPListing; WPState: TYPE = LogDB.WPState; WPStateRecord: TYPE = LogDB.WPStateRecord; WPValue: TYPE = LONG POINTER TO RECORD [ entryByteAddress: INT ]; CompareRopes: PROC[s1: ROPE, s2: ROPE, substringEqual: BOOL] RETURNS[res: BTreeSimple.Comparison] = { ss1: INT=Rope.Size[s1]; r2: ROPE_IF substringEqual THEN Rope.Substr[s2, 0, ss1] ELSE s2; RETURN [Rope.Compare[s1, r2, FALSE]]; }; wpAttrs: RefTab.Ref; logDB: WPState; InitWhitePagesDatabase: PUBLIC SAFE PROC[ fileName: ROPE, logFileName: ROPE, extIntMapName: ROPE, accessOptions: FS.AccessOptions _ $read, howToComplain: Log.WhereToReport_$System] RETURNS[wpState: WPState_NIL] = TRUSTED { buffer: REF TEXT = RefText.ObtainScratch[100]; s: IO.STREAM; logDB _ wpState _ NEW[WPStateRecord]; wpState.accessOptions _ accessOptions; IF fileName=NIL THEN fileName _ UserProfile.Token[key: "ThrushWPTreeName", default: "///Strowger/WPTree"]; wpState.treeRootName _ FS.ExpandName[fileName].fullFName; wpState.logFileName _ logFileName; IF extIntMapName=NIL THEN extIntMapName _ UserProfile.Token[key:"ThrushWPMappings", default: "/Indigo/Voice/BTree/IntExt.map"]; IF wpAttrs=NIL THEN { wpAttrs _ RefTab.Create[]; FOR attr: Attrs IN Attrs DO IF keysForAttributes[attr] # $unassigned THEN []_RefTab.Store[wpAttrs, keysForAttributes[attr], NEW[Attrs_attr]]; ENDLOOP; }; s _ FS.StreamOpen[extIntMapName]; wpState.wpExtInt _ RefTab.Create[]; WHILE ~s.EndOf[] DO ENABLE IO.EndOfStream=>EXIT; int: ATOM _ Atom.MakeAtomFromRefText[s.GetCedarToken[buffer: buffer].token]; ext: ATOM; []_s.GetChar[]; ext _ Atom.MakeAtomFromRefText[s.GetLine[buffer]]; []_wpState.wpExtInt.Store[ext, int]; -- external version is the key. ENDLOOP; s.Close[]; RefText.ReleaseScratch[buffer]; []_OpenWhitePagesDatabase[wpState, howToComplain]; }; OpenWhitePagesDatabase: SAFE PROC[ wpState: WPState, howToComplain: Log.WhereToReport_$System] RETURNS [ok: BOOL_FALSE] = TRUSTED { ENABLE BTree.Error => { Log.Problem["Trouble opening BTree", howToComplain]; CONTINUE }; treeName: ROPE_wpState.treeRootName.Concat[".Tree"]; feepTreeName: ROPE_wpState.treeRootName.Concat[".FTree"]; logFileName: ROPE _ wpState.logFileName; treeFile, feepFile: FS.OpenFile; logStream: IO.STREAM; init: BOOL; IF wpState=NIL THEN RETURN[FALSE]; IF wpState.wpOpen THEN RETURN; wpState.wpTree _ BTreeSimple.New[]; wpState.wpFeepTree _ BTreeSimple.New[]; { ENABLE FS.Error => IF error.group = user THEN { Log.Problem[error.explanation, howToComplain]; treeFile_FS.nullOpenFile; CONTINUE; }; sbp: FS.StreamBufferParms = [FS.defaultStreamBufferParms.vmPagesPerBuffer, 4]; SELECT wpState.accessOptions FROM $read => { treeFile_FS.Open[name: treeName]; feepFile_FS.Open[name: feepTreeName]; logStream _ FS.StreamOpen[fileName: logFileName, streamBufferParms: sbp]; }; $create => { treeFile_FS.Create[name: treeName, keep: 2, setKeep: TRUE, pages: 100]; feepFile_FS.Create[name: feepTreeName, keep: 2, setKeep: TRUE, pages: 100]; logStream _ FS.StreamOpen[fileName: logFileName, accessOptions: $write, streamBufferParms: sbp]; }; $write => { treeFile_FS.OpenOrCreate[name: treeName, keep: 2, pages: 100]; feepFile_FS.OpenOrCreate[name: feepTreeName, keep: 2, pages: 100]; logStream _ FS.StreamOpen[fileName: logFileName, accessOptions: $write, streamBufferParms: sbp]; }; ENDCASE => Log.Problem["Don't request $append option for BTree", howToComplain]; }; IF treeFile=NIL OR logStream = NIL OR feepFile=NIL THEN RETURN[FALSE]; wpState.wpFile _ treeFile; wpState.wpFeepFile _ feepFile; wpState.logStream _ logStream; init _ wpState.accessOptions = $create OR logStream.GetLength = 0; BTreeSimple.Open[tree: wpState.wpTree, file: wpState.wpFile, initialize: init]; BTreeSimple.Open[tree: wpState.wpFeepTree, file: wpState.wpFeepFile, initialize: init]; IF wpState.accessOptions = $create THEN wpState.accessOptions _ $write; ok _ wpState.wpOpen _ TRUE; }; CloseWhitePagesDatabase: PUBLIC SAFE PROC[wpState: WPState, howToComplain: Log.WhereToReport_$System] RETURNS [ok: BOOL_TRUE] = TRUSTED { IF wpState=NIL OR ~wpState.wpOpen THEN RETURN; BTreeSimple.SetState[wpState.wpTree, closed!BTree.Error => { ok_FALSE; CONTINUE}]; BTreeSimple.SetState[wpState.wpTree, closed!BTree.Error => { ok_FALSE; CONTINUE}]; wpState.logStream.Close[!FS.Error => IF error.group>=lock THEN CONTINUE]; wpState.wpFile.Close[!FS.Error => IF error.group>=lock THEN CONTINUE]; wpState.wpFeepFile.Close[!FS.Error => IF error.group>=lock THEN CONTINUE]; wpState.wpOpen _ FALSE; }; SetProperLength: SAFE PROC[name: ROPE] = CHECKED { pages: INT; file: FS.OpenFile _ FS.Open[name, $write]; pages _ FS.GetInfo[file].pages; FS.SetByteCountAndCreatedTime[file, FS.BytesForPages[pages]]; FS.Close[file]; }; GetEntry: PUBLIC SAFE PROC[ wpState: WPState, name: ROPE_NIL, key: ATOM_$officeNumber, feep: BOOL_FALSE, listing: WPListing _ NIL] RETURNS [fullRName: ROPE_NIL, entry: ROPE_NIL, newListing: WPListing_NIL] = TRUSTED { IF listing = NIL THEN listing _ Lookup[wpState, name, feep]; IF listing = NIL THEN RETURN; newListing _ listing; fullRName _ NARROW[listing.Fetch[$rname].val]; IF key#NIL THEN entry _ NARROW[listing.Fetch[key].val]; }; Lookup: PUBLIC SAFE PROC[ wpState: WPState, name: ROPE, feep: BOOL_FALSE ] RETURNS [ listing: WPListing_NIL ] = TRUSTED { buffer: REF TEXT _ RefText.ObtainScratch[50]; FindOne: UNSAFE PROC[key: BTreeSimple.EntryKey, value: BTreeSimple.EntryValue] RETURNS [continue: BOOLEAN_FALSE] = { wpValue: WPValue = LOOPHOLE[@value[0]]; byteAddress: INT; SELECT CompareRopes[name, BTreeSimple.KeyFromEntry[key], TRUE] FROM greater => RETURN[TRUE]; equal => NULL; ENDCASE => RETURN[FALSE]; IF feep AND listing#NIL THEN { listing _ NIL; RETURN; }; byteAddress _ wpValue.entryByteAddress; listing _ ReadEntries[wpState, byteAddress, buffer]; RETURN[feep]; }; IF wpState.wpOpen OR OpenWhitePagesDatabase[wpState] THEN []_BTreeSimple.EnumerateEntries[ tree: IF feep THEN wpState.wpFeepTree ELSE wpState.wpTree, key: name, relation: less, Proc: FindOne ]; RefText.ReleaseScratch[buffer]; }; ReadEntries: SAFE PROC[ wpState: WPState, byteAddress: INT, buffer: REF TEXT ] RETURNS [ listing: WPListing_NIL ] = TRUSTED { entry: IO.STREAM _ wpState.logStream; recordKey: ATOM; recordValue: ROPE; IF ~wpState.wpOpen AND ~OpenWhitePagesDatabase[wpState] THEN RETURN[NIL]; IF byteAddress<0 OR entry.GetLength[]<=byteAddress THEN RETURN[NIL]; entry.SetIndex[byteAddress]; listing _ NewListing[]; DO code: CHAR; IF entry.EndOf[] THEN EXIT; code _ entry.GetChar[]; SELECT code FROM '\000, '\n => EXIT; >='\200 => recordKey _ keysForAttributes[LOOPHOLE[-LOOPHOLE[code,INTEGER]]]; ENDCASE => { ENABLE IO.EndOfStream => CONTINUE; DefProc: IO.BreakProc = TRUSTED { RETURN[IF (code_char) = ': THEN break ELSE other]; }; keyRope: REF TEXT; entry.Backup[code]; keyRope _ entry.GetToken[DefProc, buffer].token; IF keyRope#NIL AND code = ': THEN { [] _ entry.GetChar[]; [] _ entry.GetChar[]; recordKey _ Atom.MakeAtomFromRefText[keyRope]; }; }; IF recordKey=NIL THEN EXIT; recordValue _ entry.GetLineRope[!IO.EndOfStream => {EXIT}]; List[listing, recordKey, recordValue]; ENDLOOP; }; Enter: SAFE PROC[wpState: WPState, listing: WPListing, byteAddress: INT] = TRUSTED { SetVal: PROC[value: BTreeSimple.EntryValue] = { LOOPHOLE[value, LONG POINTER TO CARDINAL]^ _ 2; -- Compensate BTree bug! LOOPHOLE[@value[0], LONG POINTER TO INT]^ _ byteAddress; }; name, feepName: ROPE; IF ~wpState.wpOpen AND ~OpenWhitePagesDatabase[wpState] THEN RETURN; name _ NARROW[listing.Fetch[$rname].val]; feepName _ NamesExtras.FeepName[name]; BTreeSimple.UpdateEntry[tree: wpState.wpTree, key: name, valueLength: 2, Proc: SetVal]; BTreeSimple.UpdateEntry[tree: wpState.wpFeepTree, key: feepName, valueLength: 2, Proc: SetVal]; }; WriteEntries: SAFE PROC[stream: IO.STREAM, listing: WPListing] = TRUSTED { EPA: RefTab.EachPairAction = TRUSTED { stream.PutF["%g: %g\n", atom[NARROW[key]], rope[NARROW[val]]]; RETURN[FALSE]; }; []_RefTab.Pairs[listing, EPA]; stream.PutChar['\n]; }; LogAndEnter: PUBLIC SAFE PROC[wpState: WPState, listing: WPListing] = TRUSTED { entry: IO.STREAM; byteAddress: INT; IF ~wpState.wpOpen AND ~OpenWhitePagesDatabase[wpState] THEN RETURN; entry _ wpState.logStream; byteAddress _ entry.GetLength[]; entry.SetIndex[byteAddress]; WriteEntries[entry, listing]; entry.Flush[]; Enter[wpState, listing, byteAddress]; }; PrintEntries: PUBLIC SAFE PROC[listing: WPListing] = TRUSTED { h: Commander.Handle = GetCommanderHandle[]; WriteEntries[h.out, listing]; IF h.out#h.err THEN Note[listing]; }; Note: SAFE PROC[listing: WPListing] = TRUSTED { h: Commander.Handle = GetCommanderHandle[]; name: ROPE = NARROW[listing.Fetch[$rname].val]; h.out.Put[rope[name], rope["\n"]]; }; GetCommanderHandle: PROC RETURNS[handle: Commander.Handle] = { p: Atom.PropList = ProcessProps.GetPropList[]; IF p=NIL THEN RETURN[NIL]; RETURN[NARROW[Commander.GetProperty[$CommanderHandle, p]]]; }; WhitePagesFill: SAFE PROC[cmd: Commander.Handle, accessOptions: FS.AccessOptions_$write] = TRUSTED { buffer: REF TEXT; listing: WPListing_NIL; wpState: WPState; numEntries: CARDINAL _ 0; treeRoot, intExt: ROPE; entry: IO.STREAM; byteAddress: INT; sourceFile: ROPE _ CommandToolExtras.NextArgument[cmd]; IF sourceFile=NIL THEN { Log.Problem["Source file not specified", $System]; RETURN; }; treeRoot _ CommandToolExtras.NextArgument[cmd]; intExt _ CommandToolExtras.NextArgument[cmd]; wpState _ InitWhitePagesDatabase[ treeRoot, sourceFile, intExt, accessOptions]; IF wpState=NIL THEN { Log.Problem["Problem opening B-Trees", $System]; RETURN; }; entry _ wpState.logStream; entry.SetIndex[byteAddress _ 0]; buffer _ RefText.ObtainScratch[100]; FOR numEntries: NAT IN [0..LAST[NAT]] DO ENABLE IO.EndOfStream=>EXIT; entry _ wpState.logStream; listing _ ReadEntries[wpState, byteAddress, buffer]; IF listing = NIL THEN EXIT; Note[listing]; Enter[wpState, listing, byteAddress]; byteAddress _ entry.GetIndex[]; ENDLOOP; RefText.ReleaseScratch[buffer]; (GetCommanderHandle[]).err.PutRope["-- Updates done.\n"]; []_CloseWhitePagesDatabase[wpState]; SetProperLength[wpState.treeRootName.Concat[".Tree"]]; SetProperLength[wpState.treeRootName.Concat[".FTree"]]; }; NewListing: PUBLIC SAFE PROC RETURNS[WPListing] = TRUSTED {RETURN[RefTab.Create[]];}; List: PUBLIC SAFE PROC[listing: WPListing, key: ATOM, value: ROPE] = TRUSTED { []_listing.Store[key, value]; }; FillCmdInit: Commander.CommandProc = TRUSTED { WhitePagesFill[cmd, $create]; }; FillCmd: Commander.CommandProc = TRUSTED { WhitePagesFill[cmd, $write]; }; keysForAttributes: ARRAY LogDB.Attrs OF ATOM = [ $unassigned, $name, $rName, $officeNumber, $officeDDDNumber, $outsideNumber, $officeAddress, $officeLocation, $organization, $homeAddress, $frequency, $mailSystem, $primaryKey, $unassigned, $unassigned, $unassigned ]; Commander.Register["WPFill", FillCmdInit, "WPFill (opt)> creates new set of tree files from entries in textEntriesFile"]; Commander.Register["WPRefill", FillCmd, "WPRefill (opt)> adds to set of tree files from entries in textEntriesFile"]; END. tLogDBImpl.mesa Last Edited by: Swinehart, March 24, 1985 1:31:52 pm PST Reads and write white pages data base records. Representation primitives Top-level State Key Value: Used in enumeration routines to determine actual matches Tables of mappings between small integers (wpAttrs) or external strings (wpExtInt) and attribute names LogDB Procedures Initialize Open or reopen Close, permanently, or just to get everything up to date Hack because BTrees don't go through FS, so lengths aren't right and copy doesn't work. Given name and attribute, get value Use specified B-Tree to find and read named entry name must be in form rr.xxxxxxx Returns first listing for which name is a substring, case unimportant, of the listing Given address in log file, read entries into a listing structure Given listing and log address representing it, enter into both B-Trees Given stream and listing structure, write a log or typescript listing. Given a listing, extend the log and enter the result in the B-Trees Print listing on primary output; note on error stream if primary is a file Note name of listing on error stream Subsidiary procedures Κ ζ– "Cedar" style˜headšœ™Ibody™8L™.code2šΟk ˜ M˜M˜Mšœ˜Mšœ ˜ M˜ M˜Mšœ˜M˜M˜M˜ M˜ M˜ M˜M˜Mšœ˜Mšœ˜Mšœ ˜ ——šœ ˜MšœAœœD˜’Mšœœ˜Mšœ˜Mšœœ˜Mšœœœ˜Mšœœ˜Mšœ œ˜"—™™Jšœ œ˜Jšœœ˜*—™ Mš œ œœœœœœ˜A—J˜J™8™š Οn œœœœœ˜Mšœ œ7˜Bšœ ˜ MšœR˜T—M˜—MšœI˜PM˜—Mšœ œœ œœ œœœœ˜FM˜M˜Mšœ˜Mšœ'œ˜BMšœO˜OMšœW˜WMšœ!œ ˜GMšœœ˜J˜J˜——™8šžœ œœ˜;Jš œ*œœœœ˜MJš œ œœœœ˜.Mšœ@œœ˜RMšœ@œœ˜RMš œœ œœœ˜IMš œœ œœœ˜FMš œœ œœœ˜JMšœœ˜J˜J˜——™Wš žœœœœœ˜2Jšœœ˜ Jšœœ œ˜*Jšœœ˜Jšœ"œ˜=Jšœ ˜J˜J˜——™#šžœœœœ˜Jš œœœœœœ˜LJšœœ˜Jšœ œœ œœœœ˜UJšœ œœ(˜=Jšœ œœœ˜J˜Jšœ œ˜.Jšœœœ œ˜7J˜J˜——™1šžœœœœ˜Jšœœœœ˜0Jšœœœ˜.Jšœ™J™UJšœœœ˜-šžœœœ:˜NJšœ œœ˜%Jšœœ ˜'Jšœ œ˜šœ3œ˜CJšœ œœ˜Jšœ œ˜Jšœœœ˜—Jš œœ œœ œœ˜8Jšœ'˜'J˜4Jšœ˜ J˜—šœœ!˜9˜ Jšœœœœ˜:J˜(J˜——J˜J˜J˜——™@šž œœœ˜Jšœœ œœ˜6Jšœœœ˜.Jšœœœ˜%Jšœ œ˜Jšœ œ˜Jš œœ"œœœ˜IJš œœ œœœ˜DJ˜Jšœ˜š˜Jšœœ˜ Jšœœœ˜Jšœ˜šœ˜Jšœœ˜Jšœ)œœœ˜Lšœ˜ Jšœœœ˜"šœ œ œ˜!Jšœœœœ ˜5—Jšœ  ˜J˜Jšœ0˜0šœ œœ œ˜#J˜+Jšœ.˜.J˜—J˜——Jšœ œœœ˜Jšœ!œœ˜;Jšœ&˜&Jšœ˜—J˜J˜——™Fš žœœœ4œœ˜Tšžœœ#˜/Jš œœœœœŸ˜HJš œ œœœœ˜8J˜—Jšœœ˜Jšœœ"œœ˜DJšœœ˜)J˜&JšœW˜Wšœ@˜@Jšœ˜—J˜J˜——™Fš ž œœœ œœœ˜Jšœœ˜&Jšœœ œ˜>Jšœœ˜J˜—J˜Jšœœ˜J˜J˜J˜——™Cš ž œœœœ)œ˜OJšœœœ˜Jšœ œ˜Jšœœ"œœ˜DJ˜Jšœ ˜ J˜Jšœ˜J˜J˜%J˜J˜——™Jš ž œœœœœ˜>J˜+J˜Jšœ"˜"J˜J˜——™$šžœœœœ˜/J˜+Jšœœœ˜/Jšœ"˜"J˜J˜—J˜šžœœœ˜>J˜.Jš œœœœœ˜Jšœœ.˜;J˜———šœ™š žœœœ'œœ˜dMšœœœ˜Mšœœ˜M˜Mšœ œ˜Mšœœ˜Mšœœœ˜Mšœ œ˜Mšœ œ'˜7Mšœ œœ6œ˜VMšœ/˜/Mšœ-˜-MšœO˜OMšœ œœ4œ˜QMšœ˜M˜ Mšœ$˜$š œ œœœœ˜(Mšœœœ˜M˜Mšœ4˜4Mšœ œœœ˜M˜M˜%M˜Mšœ˜—M˜M˜9M˜$Mšœ6˜6Mšœ7˜7M˜—Mš ž œ œœœœœ˜Uš žœ œœœ œœ˜NM˜M˜—šœ%œ˜.M˜M˜—šœ!œ˜*M˜M˜—šœœ œœ˜0M˜ΧM˜—M˜«M˜§Mšœ˜——…—,ό?V