<> <> <> 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.