GVInvert.mesa; HGM, November 20, 1984 9:46:45 pm PST
Copyright c 1985 by Xerox Corporation. All rights reserved.
Edited by Schroeder on March 19, 1983 2:35 pm
Hal Murray May 7, 1985 11:58:32 pm PDT
Ron Weaver August 30, 1985 11:15:05 am PDT
Hal Murray, April 7, 1986 1:00:48 am PST
John Larson, July 6, 1986 0:42:27 am PDT
DIRECTORY
Basics USING [Comparison],
Buttons USING [Button, ButtonProc, Create],
Containers USING [ChildXBound, ChildYBound, Container, Create],
Labels USING [Create, Label, Set],
Menus USING [CreateEntry, CreateMenu, InsertMenuEntry, Menu, MenuProc],
Rules USING [Create, Rule],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [CreateViewer, PaintViewer, SetMenu, SetOpenHeight],
ViewerClasses USING [Viewer],
ViewerTools USING [MakeNewTextViewer, GetContents, SetContents, SetSelection],
FS USING [StreamOpen ],
GVNames USING [CheckStamp, Expand, ExpandInfo, GetFriends, GetMembers, MemberInfo,
RListHandle, StampInfo],
Histogram,
IO USING [card, Close, Flush, PutF, PutFR, PutRope, rope, STREAM, time],
RedBlackTree USING [Create, Delete, Insert,
Key, Lookup, LookupNextLarger, LookupSmallest, Table, UserData],
Rope USING [Cat, Compare, Equal, Fetch, Length, ROPE, SkipOver, SkipTo, Substr];
GVInvert: CEDAR MONITOR
IMPORTS
Buttons, Containers, Labels, Menus, Rules, ViewerIO, ViewerOps, ViewerTools,
FS, GVNames, Histogram, IO, RedBlackTree, Rope = {
ROPE: TYPE = Rope.ROPE;
Invert: PROC = {
ParseFileNamePattern: PROC = {
f: ROPE = ViewerTools.GetContents[fileName];
starPosition: CARDINAL = Rope.SkipTo[f, 0, "*"];
IF starPosition = Rope.Length[f]
OR Rope.SkipTo[f, starPosition+1, "*"] # Rope.Length[f] THEN {
outStr.PutRope["\nFile name patterns should have exactly one *."];
ERROR inverterStopped
};
fileNamePrefix ← Rope.Substr[f, 0, starPosition];
fileNameSuffix ← Rope.Substr[f, starPosition+1, Rope.Length[f] - starPosition+1];
}; --ParseFileNamePattern--
GetRegistryGroups: PROC [r: ROPE] = {
c: CARDINAL;
target: ROPE ← Rope.Cat["groups.", r];
rLH: GVNames.RListHandle;
Labels.Set[currentName, target];
[rLH, c, ] ← MyExpand[target, FALSE];
registryList ← CONS[rLH, registryList];
totalGrp ← totalGrp + c;
UpdateCounter[totalGroups, totalGrp];
}; --GetRegistryGroups--
CreateOutputFileForRegistry: PROC [reg: ROPE] = {
data: RedBlackTree.UserData;
acceptAll: BOOL = Rope.Equal["other", reg, FALSE];
outStr.PutF["\nCreating output file for %g.", [rope[reg]]];
fH ← FS.StreamOpen[fileName: Rope.Cat[fileNamePrefix, reg, fileNameSuffix],
accessOptions: create];
fH.PutF["DL inversion for the %g registry.\n\n%t\n\n\n\n", IO.rope[reg], IO.time[]];
data ← RedBlackTree.LookupSmallest[membersTable];
UNTIL data = NIL DO
mR: REF MemberRecord ← NARROW[data];
key: ROPE ← mR.name;
IF acceptAll OR Rope.Equal[reg, ExtractRegistry[key], FALSE] THEN
{PrintMemberEntry[mR]; [] ← RedBlackTree.Delete[membersTable, key]};
data ← RedBlackTree.LookupNextLarger[membersTable, key];
ENDLOOP;
fH.Flush[];
fH.Close[];
}; -- CreateOutputFileForRegistry--
PrintMemberEntry: PROC [mR: REF MemberRecord] = {
groupPrinted: BOOLFALSE;
mbrStatus: MailStatus;
numGroups: CARDINAL ← 0;
PutGroup: PROC [group: ROPE, owners, friends: BOOL] = {
IF groupPrinted THEN fH.PutRope[", "] ELSE groupPrinted ← TRUE;
IF owners THEN fH.PutRope["Owners("];
IF friends THEN fH.PutRope["Friends("];
fH.PutRope[group];
IF owners OR friends THEN fH.PutRope[")"];
}; --PutGroup--
Labels.Set[currentName, mR.name];
fH.PutF["\n\n%g: ", IO.rope[mR.name]];
mbrStatus ← PrintMailStatus[mR.name, mR.knownToBeIndividual];
IF mR.owner#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO
IF mR.owner[j] THEN {
PutGroup[groups[j], TRUE, FALSE];
IF mbrStatus=notRegistered THEN
RecordBadMember[
tbl: badDLsTable, dl: Rope.Cat["Owners(", groups[j], ")"], mbr: mR.name];
};
ENDLOOP;
IF mR.friend#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO
IF mR.friend[j] THEN {
PutGroup[groups[j], FALSE, TRUE];
IF mbrStatus=notRegistered THEN
RecordBadMember[
tbl: badDLsTable, dl: Rope.Cat["Friends(", groups[j], ")"], mbr: mR.name];
};
ENDLOOP;
IF mR.member#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO
IF mR.member[j] THEN {
PutGroup[groups[j], FALSE, FALSE];
IF mbrStatus=notRegistered THEN
RecordBadMember[tbl: badDLsTable, dl: groups[j], mbr: mR.name];
numGroups ← numGroups + 1;
};
ENDLOOP;
IF NOT groupPrinted THEN fH.PutRope["NONE"];
IF mbrStatus=inboxes THEN gram.DataPoint[MIN[numGroups, maxGram]];
currentMbrs ← currentMbrs + 1;
UpdateCounter[currentMembers, currentMbrs];
}; --PrintMemberEntry--
Foreign: PROC [name: ROPE] RETURNS [BOOL] = {
reg: ROPE = ExtractRegistry[name];
IF foreignRegistries = NIL THEN {
c: CARDINAL;
fR: GVNames.RListHandle;
AddThem: PROC[f: ROPE] RETURNS [done: BOOL] =
{foreignRegistries[c] ← Rope.Substr[f, 0, FindLastPeriod[f]]; c ← c+1; done ← FALSE};
Labels.Set[currentName, "individuals.foreign"];
[fR, c, ] ← MyExpand["individuals.foreign", TRUE];
foreignRegistries ← NEW [RopeSequence[c]];
c ← 0;
EnumerateRList[fR, AddThem];
};
FOR i: CARDINAL IN [0 .. foreignRegistries.length) DO
IF Rope.Equal[foreignRegistries[i], reg, FALSE] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
}; --Foreign--
MailStatus: TYPE = {notRegistered, invalid, forwarded, foreign, inboxes, group};
PrintMailStatus: PROC [name: ROPE, knownToBeIndividual: BOOL]
RETURNS [status: MailStatus]= {
allDownDot: BOOLFALSE;
UNTIL Stopped[] DO
nameType: GVNames.StampInfo ← IF knownToBeIndividual
THEN individual ELSE GVNames.CheckStamp[name];
SELECT nameType FROM
group => { fH.PutRope["(group) "]; status ← group };
individual => {
rLH: GVNames.RListHandle;
c: CARDINAL;
siteList: BOOL;
Labels.Set[currentName, name];
[rLH, c, siteList] ← MyExpand[name, TRUE];
IF c = 0 THEN { fH.PutRope[" (invalid recipient)"]; status ← invalid; }
ELSE {
fH.PutRope["("];
IF ~siteList THEN { fH.PutRope["->"]; status ← forwarded }
ELSE status ← inboxes;
fH.PutRope[NameListToRope[rLH]];
fH.PutRope[") "];
};
};
notFound => {
IF Foreign[name] THEN { fH.PutRope[" (foreign registry)"]; status ← foreign }
ELSE {
fH.PutRope["(not registered) "];
status ← notRegistered; }; };
allDown => { ReportAllDown[allDownDot, name]; allDownDot←TRUE; LOOP; };
ENDCASE => ERROR;
EXIT;
ENDLOOP;
}; --PrintMailStatus--
InsertGrouplessIndividuals: PROC [reg: ROPE] = {
RecordIfNonMember: PROC [n: ROPE] RETURNS [BOOL] = {
mR: REF MemberRecord ← NARROW[RedBlackTree.Lookup[membersTable, n]];
IF mR = NIL THEN mR ← MakeTableEntry[n, TRUE];
RETURN [FALSE];
}; --RecordIfNonMember--
g: ROPE = Rope.Cat["individuals.", reg];
Labels.Set[currentName, g];
EnumerateRList[MyExpand[g, TRUE].m, RecordIfNonMember];
}; --InsertGrouplessIndividuals--
ProcessGroup: PROC [group: ROPE] RETURNS [done: BOOL] = {
ownersList: ROPE = Rope.Cat["Owners-", group];
friendsList: ROPE = Rope.Cat["Friends-", group];
doingOwners, doingFriends: BOOLFALSE;
RecordMembership: PROC [n: ROPE] RETURNS [BOOL] = {
mR: REF MemberRecord ← NARROW[RedBlackTree.Lookup[membersTable, n]];
IF mR=NIL THEN mR ← MakeTableEntry[n, FALSE];
SELECT TRUE FROM
doingOwners => {
IF mR.owner=NIL THEN
mR.owner ← NEW[Membership[groups.length]];
mR.owner[currentGrp] ← TRUE;
};
doingFriends => {
IF mR.friend=NIL THEN
mR.friend ← NEW[Membership[groups.length]];
mR.friend[currentGrp] ← TRUE;
};
ENDCASE => {
IF mR.member=NIL THEN
mR.member ← NEW[Membership[groups.length]];
mR.member[currentGrp] ← TRUE;
};
RETURN [FALSE];
}; --RecordMembership--
Labels.Set[currentName, group];
UpdateCounter[currentGroups, currentGrp+1];
EnumerateRList[MyExpand[group, TRUE].m, RecordMembership];
doingFriends ← TRUE;
EnumerateRList[MyGetFriends[group, TRUE].m, RecordMembership];
doingOwners ← TRUE;
EnumerateRList[MyExpand[ownersList, TRUE].m, RecordMembership];
groups[currentGrp] ← group;
currentGrp ← currentGrp+1;
RETURN[FALSE]
};
MakeTableEntry: PROC [n: ROPE, ind: BOOL]
RETURNS [mR: REF MemberRecord] = {
mR ← NEW [MemberRecord];
mR.name ← n;
mR.knownToBeIndividual ← ind;
mR.owner ← NIL;
mR.member ← NIL;
totalMbrs ← totalMbrs + 1;
UpdateCounter[totalMembers, totalMbrs];
RedBlackTree.Insert[membersTable, mR, n];
}; --MakeTableEntry--
UpdateCounter: PROC [l: Labels.Label, c: CARDINAL] =
{Labels.Set[l, IO.PutFR[v1: IO.card[c]] ]};
registryList: LIST OF GVNames.RListHandle ← NIL;
groups: REF RopeSequence;
foreignRegistries: REF RopeSequence ← NIL;
fH: IO.STREAM;
membersTable: RedBlackTree.Table = RedBlackTree.Create[GetKey, MyCompare];
badDLsTable: RedBlackTree.Table = RedBlackTree.Create[GetKey, MyCompare];
currentGrp, totalGrp, currentMbrs, totalMbrs: CARDINAL ← 0;
inputRegs: ROPE = ViewerTools.GetContents[registries];
fileNamePrefix: ROPE;
fileNameSuffix: ROPE;
maxGram: INT = 500;
gram: Histogram.Gram = Histogram.NewGram[0, maxGram];
outStr.PutF["Running at %t.", IO.time[]];
Labels.Set[currentName, "none"];
UpdateCounter[totalGroups, 0];
UpdateCounter[currentGroups, 0];
UpdateCounter[totalMembers, 0];
UpdateCounter[currentMembers, 0];
ParseFileNamePattern[];
ForWordsInRopeDo[inputRegs, CheckRegistryValidity];
ForWordsInRopeDo[AllRegistries[], GetRegistryGroups];
groups ← NEW [RopeSequence[totalGrp]];
FOR registryList ← registryList, registryList.rest UNTIL registryList = NIL DO
EnumerateRList[registryList.first, ProcessGroup];
ENDLOOP;
ForWordsInRopeDo[inputRegs, InsertGrouplessIndividuals];
ForWordsInRopeDo[inputRegs, CreateOutputFileForRegistry];
PrintBadMembers[badDLsTable, inputRegs];
gram.Print[outStr, "\n\nNumber of DL's for each mail system user."];
outStr.PutF["\nDone at %t.\n\n", IO.time[]];
};--Invert--
RopeSequence: TYPE = RECORD[SEQUENCE length: CARDINAL OF ROPE];
inverterStopped: ERROR = CODE;
inversionInProgress: BOOLFALSE;
allRegistries: ROPENIL;
defaultRegistries: ROPE = "AllAreas Arpa Auto BITNET CHI Cholla COM CSNET DLOS DLOSLV EDU EIS ElSegundo EOSA ES ESArea ESCP8 ESXC15 ESXC16 FX GOV Guest Henr IHAIL Internet MAILNET NS OSBUBayshore OSBUNorth OSBUSouth OSDA PA PAArea PARC PASA RX SanDiegoXCSS SBDERX Siemens Sunnyvale UK UUCP WBST WBSTArea WBST128 WBST129 X XRCC XSIS MS GV Other";
defaultFileNamePattern: ROPE = "///GV/*.txt";
stop: BOOLFALSE;
DoIt: Menus.MenuProc = {
IF ~ReserveInverter[] THEN RETURN;
Invert[ ! inverterStopped => {outStr.PutF["\nStopped at %t.\n\n", IO.time[]]; CONTINUE} ];
outStr.Flush[];
ReleaseInverter[];
}; -- DoIt--
StopIt: Menus.MenuProc = {SetStop[]};
ReserveInverter: ENTRY PROC RETURNS [BOOL] = {
IF inversionInProgress THEN RETURN [FALSE]
ELSE {inversionInProgress ← TRUE; RETURN[TRUE]};
};
ReleaseInverter: ENTRY PROC = {inversionInProgress ← FALSE; stop ← FALSE};
SetStop: ENTRY PROC = {stop ← TRUE};
StopSet: ENTRY PROC RETURNS [BOOL] = {RETURN [stop]};
Stopped: PROC RETURNS [BOOL] = {
IF StopSet[] THEN ERROR inverterStopped ELSE RETURN[FALSE]};
AllRegistries: PROC RETURNS[ROPE] = {
ExtractRegistry: PROC [r: ROPE] RETURNS [done: BOOL] = {
allRegistries ← Rope.Cat[allRegistries, " ", Rope.Substr[r, 0, FindLastPeriod[r]]];
done ← FALSE;
};
IF allRegistries = NIL THEN {
Labels.Set[currentName, "groups.gv"];
EnumerateRList[ MyExpand["groups.gv", FALSE].m, ExtractRegistry];
};
RETURN [ allRegistries ];
}; --AllRegistries--
FindLastPeriod: PROC[r: ROPE] RETURNS [lastPeriod: CARDINAL] = {
FOR i: INT DECREASING IN [0 .. Rope.Length[r]) DO
IF Rope.Fetch[r, i] = '. THEN {lastPeriod ← i; EXIT};
REPEAT FINISHED => lastPeriod ← Rope.Length[r];
ENDLOOP;
}; --FindLastPeriod--
ReportAllDown: PROC [dot: BOOL, name: ROPE] = {
IF dot
THEN outStr.PutRope["."]
ELSE outStr.PutF["\nAll down: %g. ", [rope[name]]];
};
MyExpand: PROC [eName: ROPE, ignoreNotFound: BOOL]
RETURNS [m: GVNames.RListHandle, c: CARDINAL, isSiteList: BOOL] = {
printDot: BOOLFALSE;
ReportNotFound: PROC =
{outStr.PutF["%g%g\n\n", [rope[eName]], [rope[" not found."]]]; ERROR inverterStopped};
UNTIL Stopped[] DO
WITH GVNames.Expand[eName] SELECT FROM
g: GVNames.ExpandInfo[group] =>
{m ← g.members; c ← g.count; isSiteList ← FALSE};
i: GVNames.ExpandInfo[individual] =>
{m ← i.sites; c ← i.count; isSiteList ← TRUE};
n: GVNames.ExpandInfo[notFound] =>
WITH GVNames.GetMembers[eName] SELECT FROM
g: GVNames.MemberInfo[group] =>
{m ← g.members; c ← g.count; isSiteList ← FALSE};
n: GVNames.MemberInfo[notFound] =>
IF ignoreNotFound THEN {m ← NIL; c ← 0}
ELSE ReportNotFound[];
a: GVNames.MemberInfo[allDown] =>
{ReportAllDown[printDot, eName]; printDot ← TRUE; LOOP};
ENDCASE => ERROR;
a: GVNames.ExpandInfo[allDown] =>
{ReportAllDown[printDot, eName]; printDot ← TRUE; LOOP};
ENDCASE => ERROR;
EXIT;
ENDLOOP;
}; --MyExpand--
MyGetFriends: PROC [eName: ROPE, ignoreNotFound: BOOL]
RETURNS [m: GVNames.RListHandle, c: CARDINAL, isSiteList: BOOL] = {
printDot: BOOLFALSE;
ReportNotFound: PROC =
{outStr.PutF["%g%g\n\n", [rope[eName]], [rope[" not found."]]]; ERROR inverterStopped};
UNTIL Stopped[] DO
WITH GVNames.GetFriends[eName] SELECT FROM
g: GVNames.MemberInfo[group] =>
{m ← g.members; c ← g.count; isSiteList ← FALSE};
i: GVNames.MemberInfo[individual] => ERROR;
n: GVNames.MemberInfo[notFound] =>
IF ignoreNotFound THEN {m ← NIL; c ← 0; isSiteList ← FALSE}
ELSE ReportNotFound[];
a: GVNames.MemberInfo[allDown] =>
{ReportAllDown[printDot, eName]; printDot ← TRUE; LOOP};
ENDCASE => ERROR;
EXIT;
ENDLOOP;
};
ExtractRegistry: PROC [RName: ROPE] RETURNS [registry: ROPE] = {
start: CARDINAL ← FindLastPeriod[RName]+1;
RETURN [IF start >= Rope.Length[RName]
THEN NIL ELSE Rope.Substr[RName, start, Rope.Length[RName] - start]]
}; --ExtractRegistry--
NameListToRope: PROC [mLH: GVNames.RListHandle] RETURNS [r: ROPE] = {
AddMemberToRope: PROC[m: ROPE] RETURNS [done: BOOL] = {
IF r # NIL THEN r ← Rope.Cat[r, ", "];
r ← Rope.Cat[r, m];
done ← FALSE
};
r ← NIL;
EnumerateRList[mLH, AddMemberToRope];
}; --NameListToRope--
ForWordsInRopeDo: PROC [r: ROPE, work: PROC[ROPE]] = {
parsePosition: CARDINAL ← Rope.SkipOver[r, 0, " "]; -- skip initial blanks
UNTIL parsePosition = Rope.Length[r] DO --parse registry input--
start: CARDINAL = parsePosition;
parsePosition ← Rope.SkipTo[r, parsePosition, " "];
work[Rope.Substr[r, start, parsePosition-start]];
parsePosition ← Rope.SkipOver[r, parsePosition, " "];
ENDLOOP;
}; -- ForWordsInRopeDo --
EnumerateRList: PROC [r: GVNames.RListHandle,
p: PROC [ROPE] RETURNS [BOOL] ] =
{FOR r ← r, r.rest UNTIL r=NIL OR p[r.first] DO ENDLOOP};
ValidNameWithStar: PROC [reg: ROPE] RETURNS [ok: BOOL] = {
printDot: BOOLFALSE;
length: INT ← Rope.Length[reg];
IF Rope.Equal[reg, "*"] THEN RETURN [TRUE];
IF length < 3 THEN RETURN [FALSE];
IF Rope.Fetch[reg, 0] # '* THEN RETURN [FALSE];
IF Rope.Fetch[reg, 1] # '. THEN RETURN [FALSE];
reg ← Rope.Substr[reg, 2, length-2];
UNTIL Stopped[] DO
name: ROPE ← Rope.Cat[reg, ".gv"];
SELECT GVNames.CheckStamp[name] FROM
group => RETURN [TRUE];
individual => RETURN [FALSE];
notFound => RETURN [FALSE];
allDown =>
{ReportAllDown[printDot, name]; printDot←TRUE; LOOP};
ENDCASE => ERROR;
Can't get here
ENDLOOP;
};
CheckRegistryValidity: PROC [reg: ROPE] = {
printDot: BOOLFALSE;
ReportInvalidRegistry: PROC = {
outStr.PutF["%g%g\n\n", [rope[reg]], [rope[" is not a valid registry."]]];
ERROR inverterStopped;
};
IF Rope.Equal["other", reg, FALSE] THEN RETURN;
UNTIL Stopped[] DO
name: ROPE ← Rope.Cat[reg, ".gv"];
SELECT GVNames.CheckStamp[name] FROM
group => NULL;
individual => ReportInvalidRegistry[];
notFound => {
name ← Rope.Cat[reg, ".foreign"];
SELECT GVNames.CheckStamp[name] FROM
group, notFound =>
ReportInvalidRegistry[];
individual =>
NULL;
allDown =>
{ReportAllDown[printDot, name]; printDot←TRUE; LOOP};
ENDCASE => ERROR;
};
allDown =>
{ReportAllDown[printDot, name]; printDot←TRUE; LOOP};
ENDCASE => ERROR;
EXIT;
ENDLOOP;
}; --CheckRegistryValidity--
BadDL: TYPE = RECORD [name: ROPE, badMbr: LIST OF ROPE];
RecordBadMember: PROC [tbl: RedBlackTree.Table, dl, mbr: ROPE] = {
dlEntry: REF BadDL;
IF ValidNameWithStar[mbr] THEN RETURN;
dlEntry ← NARROW[RedBlackTree.Lookup[tbl, dl]];
IF dlEntry = NIL THEN {
dlEntry ← NEW[BadDL];
dlEntry.name ← dl;
dlEntry.badMbr ← NIL;
RedBlackTree.Insert[tbl, dlEntry, dl];
};
dlEntry.badMbr ← CONS[mbr, dlEntry.badMbr];
}; --RecordBadMember--
PrintBadMembers: PROC [tbl: RedBlackTree.Table, inputRegistries: ROPE] = {
PrintBadDLsForRegistry: PROC [reg: ROPE] = {
needRegistryLabel: BOOLTRUE;
acceptAll: BOOL = Rope.Equal["other", reg, FALSE];
data: RedBlackTree.UserData;
data ← RedBlackTree.LookupSmallest[tbl];
UNTIL data = NIL DO
dl: REF BadDL ← NARROW[data];
key: ROPE ← dl.name;
IF Rope.Equal[reg, ExtractRegistry[key], FALSE] OR acceptAll THEN
{
firstName: BOOLTRUE;
IF needRegistryLabel THEN {
IF needTitle THEN {
outStr.PutRope["\n\n\nDL's with members that are NOT REGISTERED."];
needTitle ← FALSE;
};
outStr.PutF["\n\n\n""%g"" registry:\n", IO.rope[reg]];
needRegistryLabel ← FALSE;
};
Labels.Set[currentName, dl.name];
outStr.PutF["\n\n%g -- ", IO.rope[key]];
FOR mbr: LIST OF ROPE ← dl.badMbr, mbr.rest UNTIL mbr=NIL DO
IF firstName THEN firstName ← FALSE ELSE outStr.PutRope[", "];
outStr.PutRope[mbr.first];
ENDLOOP;
[] ← RedBlackTree.Delete[tbl, key];
};
data ← RedBlackTree.LookupNextLarger[tbl, key];ENDLOOP;
}; --PrintBadDLsForRegistry--
needTitle: BOOLTRUE;
ForWordsInRopeDo[inputRegistries, PrintBadDLsForRegistry];
IF needTitle THEN outStr.PutRope["No bad members.\n"]
}; --PrintBadMembers--
Membership: TYPE = RECORD[PACKED SEQUENCE length: CARDINAL OF BOOL];
MemberRecord: TYPE = RECORD[name: ROPE, knownToBeIndividual: BOOL,
owner, friend, member: REF Membership];
GetKey: PROC [data: RedBlackTree.UserData] RETURNS [key: RedBlackTree.Key] = {
WITH data SELECT FROM
m: REF MemberRecord => key ← m.name;
d: REF BadDL => key ← d.name;
r: ROPE => key ← r;
ENDCASE => ERROR;
};
MyCompare: PROC [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison] = {
a: ROPENARROW[k];
b: ROPENARROW[GetKey[data]];
RETURN [Rope.Compare[a, b, FALSE]]
}; --compareMbrs--
**************** Viewers set up stuff ****************
entryHeight: CARDINAL = 15;
entryVSpace: CARDINAL = 10;
entryHSpace: CARDINAL = 10;
heightSoFar: CARDINAL ← 0;
container: Containers.Container;
currentMembers, totalMembers: Labels.Label;
currentGroups, totalGroups: Labels.Label;
currentName: Labels.Label;
exceptions: ViewerClasses.Viewer;
inStr, outStr: IO.STREAM;
fileName, registries: ViewerClasses.Viewer;
BuildOuter: PROC = {
myMenu: Menus.Menu ← Menus.CreateMenu[];
container ← Containers.Create[info: [name: "InvertDLs", scrollable: FALSE] ];
Menus.InsertMenuEntry[menu: myMenu,
entry: Menus.CreateEntry[name: "DoIt", proc: DoIt]
];
Menus.InsertMenuEntry[menu: myMenu,
entry: Menus.CreateEntry[name: "Stop", proc: StopIt]
];
ViewerOps.SetMenu[viewer: container, menu: myMenu];
BuildUserInput[];
BuildUserFeedback[];
BuildExceptions[];
ViewerOps.SetOpenHeight[viewer: container, clientHeight: heightSoFar];
ViewerOps.PaintViewer[viewer: container, hint: all];
};
BuildUserInput: PROC = {
l1, l2: Buttons.Button;
heightSoFar ← heightSoFar+entryVSpace/2;
l1 ← Buttons.Create[info: [name: "File name pattern (* for registry):",
parent: container, border: FALSE, wy: heightSoFar], proc: ForceSelToFileName];
fileName ← ViewerTools.MakeNewTextViewer[info: [parent: container,
wx: l1.wx+l1.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: entryHeight,
data: defaultFileNamePattern, scrollable: FALSE, border: FALSE], paint: FALSE];
Containers.ChildXBound[container, fileName];
heightSoFar ← heightSoFar+entryVSpace+l1.wh;
l2 ← Buttons.Create[info: [name: "Registries:", parent: container,
border: FALSE, wy: heightSoFar], proc: ForceSelToRegistries];
registries ← ViewerTools.MakeNewTextViewer[info: [parent: container,
wx: l2.wx+l2.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: 3*entryHeight,
data: defaultRegistries, scrollable: TRUE, border: FALSE], paint: FALSE];
Containers.ChildXBound[container, registries];
heightSoFar ← heightSoFar+entryVSpace+registries.wh;
};
ForceSelToFileName: Buttons.ButtonProc = {
IF mouseButton#red
THEN ViewerTools.SetContents[fileName, defaultFileNamePattern]
ELSE ViewerTools.SetSelection[fileName];
};
ForceSelToRegistries: Buttons.ButtonProc = {
IF mouseButton#red
THEN ViewerTools.SetContents[registries, defaultRegistries]
ELSE ViewerTools.SetSelection[registries];
};
BuildUserFeedback: PROC = {
li, lg, ln, of: Labels.Label;
r1: Rules.Rule;
r1 ← Rules.Create[info: [parent: container, wx: 0, wy: heightSoFar, ww: 0, wh:1]];
Containers.ChildXBound[container, r1];
heightSoFar ← heightSoFar+entryVSpace;
li ← Labels.Create[info: [name: "Members:", parent: container, wx: 0, wy: heightSoFar,
border: FALSE]];
currentMembers ← Labels.Create[info: [name: "0000", parent: container,
wx: li.wx+li.ww+entryHSpace, wy: heightSoFar, border: TRUE]];
Labels.Set[currentMembers, "0"];
of ← Labels.Create[info: [name: "of", parent: container,
wx: currentMembers.wx+currentMembers.ww+entryHSpace, wy: heightSoFar, border: FALSE]];
totalMembers ← Labels.Create[info: [name: "0000", parent: container,
wx: of.wx+of.ww+entryHSpace, wy: heightSoFar, border: TRUE]];
Labels.Set[totalMembers, "0"];
lg ← Labels.Create[info: [name: "Groups:", parent: container,
wx: totalMembers.wx+totalMembers.ww+entryHSpace+entryHSpace, wy: heightSoFar,
border: FALSE]];
currentGroups ← Labels.Create[info: [name: "0000", parent: container,
wx: lg.wx+lg.ww+entryHSpace, wy: heightSoFar, border: TRUE]];
Labels.Set[currentGroups, "0"];
of ← Labels.Create[info: [name: "of", parent: container,
wx: currentGroups.wx+currentGroups.ww+entryHSpace, wy: heightSoFar, border: FALSE]];
totalGroups ← Labels.Create[info: [name: "0000", parent: container, wx: of.wx+of.ww+entryHSpace,
wy: heightSoFar, border: TRUE]];
Labels.Set[totalGroups, "0"];
heightSoFar ← heightSoFar+entryVSpace+of.wh;
ln ← Labels.Create[info: [name: "Current Name:", parent: container, wx: 0, wy: heightSoFar,
border: FALSE]];
currentName ← Labels.Create[info: [name: "", parent: container, wx: ln.wx+ln.ww+entryHSpace,
wy: heightSoFar, border: FALSE]];
Labels.Set[currentName, "none"];
Containers.ChildXBound[container, currentName];
heightSoFar ← heightSoFar+entryVSpace+of.wh;
};
BuildExceptions: PROC = {
r2: Rules.Rule;
r2 ← Rules.Create[info: [parent: container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]];
Containers.ChildXBound[container, r2];
heightSoFar ← heightSoFar+entryVSpace;
exceptions ← ViewerOps.CreateViewer[flavor: $Typescript,
info: [name: "", parent: container, wx: 0, wy: heightSoFar, wh: 5*entryHeight,
border: FALSE]];
heightSoFar ← heightSoFar+exceptions.wh;
Containers.ChildXBound[container, exceptions];
Containers.ChildYBound[container, exceptions];
[in: inStr, out: outStr] ← ViewerIO.CreateViewerStreams[name: "", viewer: exceptions,
backingFile: "InvertDLs.log"];
};
******************** Initialization ********************--
BuildOuter[];
}..