PhoneListImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Eric Nickell, October 30, 1985 11:44:43 am PST
Last Edited by: Gasbarro October 14, 1985 7:28:09 pm PDT
DIRECTORY
BitTableLookup, Commander, CommandTool, FS, IO, MessageWindow, PhoneList, PrincOpsUtils, Process, Rope, SpellingCorrection, SymTab, UserProfile;
PhoneListImpl: CEDAR MONITOR
IMPORTS BitTableLookup, Commander, CommandTool, FS, IO, MessageWindow, PrincOpsUtils, Process, Rope, SpellingCorrection, SymTab, UserProfile
EXPORTS PhoneList
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
This is the monitored data
phoneList: SymTab.Ref ← NIL; --This is the monitored data
phoneListUPEntry: ROPENIL;
ExtractNames: PROC [line: ROPE, action: PROC [ROPE]] ~ {
Break: IO.BreakProc = {
[char: CHAR] RETURNS [IO.CharClass]
RETURN [SELECT char FROM
IN ['a..'z], IN ['A..'Z] => other,
ENDCASE => sepr];
};
ris: IO.STREAM ~ IO.RIS[rope: line];
DO
{
rope: ROPEIO.GetTokenRope[stream: ris, breakProc: Break ! IO.EndOfStream => GOTO Exit].token;
action[rope];
IF Rope.Length[rope]>1 AND Rope.Fetch[rope, 1] IN ['A..'Z] THEN {
WHILE Rope.Length[base: rope]>1 AND Rope.Fetch[base: rope, index: 1] IN ['A..'Z] DO
rope ← Rope.Substr[base: rope, start: 1];
ENDLOOP;
action[rope]; --With extra leading caps stripped
};
EXITS Exit => EXIT
};
ENDLOOP;
};
CallWhenProfileChanges: ENTRY UserProfile.ProfileChangedProc ~ {
ENABLE UNWIND => NULL;
ProfileChangedProc: TYPE = PROC [reason: ProfileChangeReason];
ProfileChangeReason: TYPE = {firstTime, rollBack, edit};
fileName: LIST OF ROPE ~ UserProfile.ListOfTokens[key: "PhoneList.Files", default: NIL];
upEntry: ROPE ~ UserProfile.Line[key: "PhoneList.Files", default: NIL];
IF fileName=NIL THEN MessageWindow.Append[message: "No phone list specified in the User Profile!", clearFirst: TRUE];
IF reason=edit AND Rope.Equal[upEntry, phoneListUPEntry] THEN RETURN; --User edited the profile, but didn't change this entry, so leave alone
Here, we know that the user changed the PhoneList.Files entry.
phoneList ← SymTab.Create[mod: 101, case: FALSE];
FOR each: LIST OF ROPE ← fileName, each.rest UNTIL each=NIL DO
ENABLE FS.Error => {
MessageWindow.Append[message: Rope.Cat["Phonelist problem: ", error.explanation], clearFirst: TRUE];
LOOP;
};
stream: IO.STREAM ~ FS.StreamOpen[fileName: each.first];
{
DO
LineBreak: IO.BreakProc ~ {
BreakProc: TYPE = PROC [char: CHAR] RETURNS [CharClass];
RETURN [IF char='\n THEN sepr ELSE other];
};
line: ROPE ~ IO.GetTokenRope[stream: stream, breakProc: LineBreak ! IO.EndOfStream => GOTO Finished].token;
Install: INTERNAL PROC [key: ROPE] ~ {
lines: LIST OF ROPE ~ CONS[line, LookupNameInternal[key].line];
[] ← SymTab.Store[x: phoneList, key: key, val: lines];
};
ExtractNames[line, Install]; --Install under each name found
ENDLOOP;
EXITS Finished => NULL;
};
ENDLOOP;
[] ← ActivateSpellingCorrection[reinitialize: TRUE];
};
Lookup: Commander.CommandProc ~ {
args: CommandTool.ArgumentVector ~ CommandTool.Parse[cmd: cmd];
foundAny: BOOLEANFALSE;
FOR arg: CARDINAL IN [1..args.argc) DO
found: BOOL;
line: LIST OF ROPE;
[found, line] ← LookupName[args[arg]];
foundAny ← foundAny OR found;
IF found THEN {
FOR each: LIST OF ROPE ← line, each.rest UNTIL each=NIL DO
IO.PutRope[self: cmd.out, r: Rope.Cat[each.first, "\n"]];
ENDLOOP;
}
ELSE {
corrections: LIST OF ROPE ~ CorrectionToName[args[arg]];
IF corrections=NIL THEN IO.PutRope[self: cmd.out, r: Rope.Cat[args[arg], " not found.\n"]]
ELSE {
IO.PutRope[self: cmd.out, r: Rope.Cat[args[arg], " not found. Possible corrections:\n"]];
FOR each: LIST OF ROPE ← corrections, each.rest UNTIL each=NIL DO
[found, line] ← LookupName[each.first];
foundAny ← foundAny OR found;
IF found THEN {
FOR each: LIST OF ROPE ← line, each.rest UNTIL each=NIL DO
IO.PutRope[self: cmd.out, r: Rope.Cat[each.first, "\n"]];
ENDLOOP;
}
ENDLOOP;
IO.PutRope[self: cmd.out, r: "\n"];
};
};
ENDLOOP;
IF ~foundAny THEN RETURN [result: $Failure];
};
LookupNameInternal: INTERNAL PROC [name: ROPE] RETURNS [found: BOOL, line: LIST OF ROPE] ~ {
ref: REF;
[found, ref] ← SymTab.Fetch[x: phoneList, key: name];
line ← NARROW[ref, LIST OF ROPE];
};
LookupName: PUBLIC ENTRY PROC [name: ROPE] RETURNS [found: BOOL, line: LIST OF ROPE] ~ {
ENABLE UNWIND => NULL;
[found, line] ← LookupNameInternal[name];
};
spellingActivated: BOOLFALSE;
bitTable: BitTableLookup.Table;
buffer: REF TEXT ~ NEW[TEXT[20]];
ActivateSpellingCorrection: INTERNAL PROC [reinitialize: BOOLFALSE] RETURNS [failed: BOOLTRUE] ~ {
RETURN [~PrincOpsUtils.IsBound[LOOPHOLE[SpellingCorrection.BruteForceCorrection]]];
};
ActivateSpellingCorrection: INTERNAL PROC [reinitialize: BOOLFALSE] RETURNS [failed: BOOLTRUE] ~ {
SELECT TRUE FROM
spellingActivated AND ~reinitialize => RETURN [FALSE];
PrincOpsUtils.IsBound[LOOPHOLE[SpellingCorrection.BruteForceCorrection]] AND PrincOpsUtils.IsBound[LOOPHOLE[BitTableLookup.Lookup]] => {
InsertNameInTable: SymTab.EachPairAction = {
[key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL]
BitTableLookup.Insert[bitTable, Rope.ToRefText[base: key]];
RETURN [FALSE];
};
bitTable ← BitTableLookup.Create[20000];
[] ← SymTab.Pairs[x: phoneList, action: InsertNameInTable];
spellingActivated ← TRUE;
RETURN [FALSE];
};
ENDCASE => RETURN [TRUE];
};
CorrectionToName: PUBLIC ENTRY PROC [name: ROPE] RETURNS [possibilities: LIST OF ROPENIL] ~ {
ENABLE UNWIND => NULL;
SeeIfInWordTable: PROC [r: REF TEXT] RETURNS [BOOL] ~ {
Process.CheckForAbort[];
RETURN [SymTab.Fetch[x: phoneList, key: Rope.FromRefText[s: r]].found];
};
SeeIfInBitTable: PROC [r: REF TEXT] RETURNS [BOOL] ~ {
RETURN [BitTableLookup.Lookup[bitTable, r]];
};
IF ActivateSpellingCorrection[] THEN RETURN[NIL];
possibilities ← SpellingCorrection.BruteForceCorrection[name, SeeIfInWordTable, buffer].corrections;
};
UserProfile.CallWhenProfileChanges[proc: CallWhenProfileChanges];
Commander.Register[key: "PhoneNumberOf", proc: Lookup, doc: "Look up phone numbers from maintained list (PhoneNumberOf lastName lastName ...)"];
END.