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;
~
BEGIN
ROPE: TYPE ~ Rope.ROPE;
This is the monitored data
phoneList: SymTab.Ref ← NIL; --This is the monitored data
phoneListUPEntry: ROPE ← NIL;
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: ROPE ← IO.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: BOOLEAN ← FALSE;
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: BOOL ← FALSE;
bitTable: BitTableLookup.Table;
buffer: REF TEXT ~ NEW[TEXT[20]];
ActivateSpellingCorrection:
INTERNAL
PROC [reinitialize:
BOOL ←
FALSE]
RETURNS [failed:
BOOL ←
TRUE] ~ {
RETURN [~PrincOpsUtils.IsBound[LOOPHOLE[SpellingCorrection.BruteForceCorrection]]];
};
ActivateSpellingCorrection: INTERNAL PROC [reinitialize: BOOL ← FALSE] RETURNS [failed: BOOL ← TRUE] ~ {
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
ROPE ←
NIL] ~ {
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 ...)"];