GVInvert.mesa; HGM, November 20, 1984 9:46:45 pm PST
Copyright © 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
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 =
BEGIN
ROPE: TYPE = Rope.ROPE;
Invert: PROCEDURE =
BEGIN
ParseFileNamePattern: PROCEDURE =
BEGIN
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 BEGIN
outStr.PutRope["\nFile name patterns should have exactly one *."];
ERROR inverterStopped
END;
fileNamePrefix ← Rope.Substr[f, 0, starPosition];
fileNameSuffix ← Rope.Substr[f, starPosition+1, Rope.Length[f] - starPosition+1];
END; --ParseFileNamePattern--
GetRegistryGroups: PROCEDURE [r: ROPE] =
BEGIN
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];
END; --GetRegistryGroups--
CreateOutputFileForRegistry: PROCEDURE [reg: ROPE] =
BEGIN
data: RedBlackTree.UserData;
acceptAll: BOOLEAN = 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[];
END; -- CreateOutputFileForRegistry--
PrintMemberEntry: PROCEDURE [mR: REF MemberRecord] =
BEGIN
groupPrinted: BOOLEANFALSE;
mbrStatus: MailStatus;
numGroups: CARDINAL ← 0;
PutGroup: PROC [group: ROPE, owners, friends: BOOLEAN] =
BEGIN
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[")"];
END; --PutGroup--
Labels.Set[currentName, mR.name];
fH.PutF["\n\n%g", IO.rope[mR.name]];
mbrStatus ← PrintMailStatus[mR.name, mR.knownToBeIndividual];
fH.PutRope[" -- "];
IF mR.owner#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO
IF mR.owner[j] THEN BEGIN
PutGroup[groups[j], TRUE, FALSE];
IF mbrStatus=notRegistered THEN
RecordBadMember[
tbl: badDLsTable, dl: Rope.Cat["Owners(", groups[j], ")"], mbr: mR.name];
END;
ENDLOOP;
IF mR.friend#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO
IF mR.friend[j] THEN BEGIN
PutGroup[groups[j], FALSE, TRUE];
IF mbrStatus=notRegistered THEN
RecordBadMember[
tbl: badDLsTable, dl: Rope.Cat["Friends(", groups[j], ")"], mbr: mR.name];
END;
ENDLOOP;
IF mR.member#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO
IF mR.member[j] THEN BEGIN
PutGroup[groups[j], FALSE, FALSE];
IF mbrStatus=notRegistered THEN
RecordBadMember[tbl: badDLsTable, dl: groups[j], mbr: mR.name];
numGroups ← numGroups + 1;
END;
ENDLOOP;
IF NOT groupPrinted THEN fH.PutRope["NONE"];
IF mbrStatus=inboxes THEN gram.DataPoint[MIN[numGroups, maxGram]];
currentMbrs ← currentMbrs + 1;
UpdateCounter[currentMembers, currentMbrs];
END; --PrintMemberEntry--
Foreign: PROCEDURE [name: ROPE] RETURNS [BOOLEAN] =
BEGIN
reg: ROPE = ExtractRegistry[name];
IF foreignRegistries = NIL THEN BEGIN
c: CARDINAL;
fR: GVNames.RListHandle;
AddThem: PROCEDURE[f: ROPE] RETURNS [done: BOOLEAN] =
{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];
END;
FOR i: CARDINAL IN [0 .. foreignRegistries.length) DO
IF Rope.Equal[foreignRegistries[i], reg, FALSE] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END; --Foreign--
MailStatus: TYPE = {notRegistered, invalid, forwarded, foreign, inboxes, group};
PrintMailStatus: PROCEDURE [name: ROPE, knownToBeIndividual: BOOLEAN]
RETURNS [status: MailStatus]=
BEGIN
allDownDot: BOOLEANFALSE;
UNTIL Stopped[] DO
nameType: GVNames.StampInfo ← IF knownToBeIndividual
THEN individual ELSE GVNames.CheckStamp[name];
SELECT nameType FROM
group =>
{ fH.PutRope[" (group)"]; status ← group };
individual => BEGIN
rLH: GVNames.RListHandle;
c: CARDINAL;
siteList: BOOLEAN;
Labels.Set[currentName, name];
[rLH, c, siteList] ← MyExpand[name, TRUE];
IF c = 0
THEN { fH.PutRope[" (invalid recipient)"]; status ← invalid }
ELSE BEGIN
fH.PutRope[" ("];
IF NOT siteList
THEN { fH.PutRope["->"]; status ← forwarded }
ELSE status ← inboxes;
fH.PutRope[NameListToRope[rLH]];
fH.PutRope[")"];
END;
END;
notFound =>
IF Foreign[name]
THEN { fH.PutRope[" (foreign registry)"]; status ← foreign }
ELSE BEGIN
fH.PutRope[" (not registered)"];
status ← notRegistered;
END;
allDown =>
{ReportAllDown[allDownDot, name]; allDownDot←TRUE; LOOP};
ENDCASE => ERROR;
EXIT;
ENDLOOP;
END; --PrintMailStatus--
InsertGrouplessIndividuals: PROCEDURE [reg: ROPE] =
BEGIN
RecordIfNonMember: PROCEDURE [n: ROPE] RETURNS [BOOLEAN] =
BEGIN
mR: REF MemberRecord ← NARROW[RedBlackTree.Lookup[membersTable, n]];
IF mR = NIL THEN mR ← MakeTableEntry[n, TRUE];
RETURN [FALSE];
END; --RecordIfNonMember--
g: ROPE = Rope.Cat["individuals.", reg];
Labels.Set[currentName, g];
EnumerateRList[MyExpand[g, TRUE].m, RecordIfNonMember];
END; --InsertGrouplessIndividuals--
ProcessGroup: PROCEDURE [group: ROPE] RETURNS [done: BOOLEAN] =
BEGIN
ownersList: ROPE = Rope.Cat["Owners-", group];
friendsList: ROPE = Rope.Cat["Friends-", group];
doingOwners, doingFriends: BOOLEANFALSE;
RecordMembership: PROCEDURE [n: ROPE] RETURNS [BOOLEAN] =
BEGIN
mR: REF MemberRecord ← NARROW[RedBlackTree.Lookup[membersTable, n]];
IF mR=NIL THEN mR ← MakeTableEntry[n, FALSE];
SELECT TRUE FROM
doingOwners =>
BEGIN
IF mR.owner=NIL THEN
mR.owner ← NEW[Membership[groups.length]];
mR.owner[currentGrp] ← TRUE;
END;
doingFriends =>
BEGIN
IF mR.friend=NIL THEN
mR.friend ← NEW[Membership[groups.length]];
mR.friend[currentGrp] ← TRUE;
END;
ENDCASE =>
BEGIN
IF mR.member=NIL THEN
mR.member ← NEW[Membership[groups.length]];
mR.member[currentGrp] ← TRUE;
END;
RETURN [FALSE];
END; --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]
END;
MakeTableEntry: PROCEDURE [n: ROPE, ind: BOOLEAN]
RETURNS [mR: REF MemberRecord] =
BEGIN
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];
END; --MakeTableEntry--
UpdateCounter: PROCEDURE [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[]];
END;--Invert--
RopeSequence: TYPE = RECORD[SEQUENCE length: CARDINAL OF ROPE];
inverterStopped: ERROR = CODE;
inversionInProgress: BOOLEANFALSE;
allRegistries: ROPENIL;
defaultRegistries: ROPE = "Arpa BITNET CHI Cholla COM CSNET DC DLOS EDU EOSA ES FX Guest Henr LB MAILNET NS OGC OSBUBayshore OSBUNorth OSBUSouth OSDA PA PASA RX SBDERX Siemens STHQ SV WBST X XRCC MS GV Other";
defaultFileNamePattern: ROPE = "///GV/*.txt";
stop: BOOLEANFALSE;
DoIt: Menus.MenuProc =
BEGIN
IF ReserveInverter[] THEN
BEGIN
Invert[ ! inverterStopped => {outStr.PutF["\nStopped at %t.\n\n", IO.time[]]; CONTINUE} ];
outStr.Flush[];
ReleaseInverter[];
END;
END; -- DoIt--
StopIt: Menus.MenuProc =
{SetStop[]};
ReserveInverter: ENTRY PROCEDURE RETURNS [BOOLEAN] =
BEGIN
IF inversionInProgress
THEN RETURN [FALSE]
ELSE {inversionInProgress ← TRUE; RETURN[TRUE]};
END;
ReleaseInverter: ENTRY PROCEDURE =
{inversionInProgress ← FALSE; stop ← FALSE};
SetStop: ENTRY PROCEDURE =
{stop ← TRUE};
StopSet: ENTRY PROCEDURE RETURNS [BOOLEAN] = INLINE
{RETURN [stop]};
Stopped: PROCEDURE RETURNS [BOOLEAN] =
{IF StopSet[] THEN ERROR inverterStopped ELSE RETURN[FALSE]};
AllRegistries: PROCEDURE RETURNS[ROPE] =
BEGIN
ExtractRegistry: PROCEDURE [r: ROPE] RETURNS [done: BOOLEAN] =
BEGIN
allRegistries ← Rope.Cat[allRegistries, " ", Rope.Substr[r, 0, FindLastPeriod[r]]];
done ← FALSE;
END;
IF allRegistries = NIL THEN {
Labels.Set[currentName, "groups.gv"];
EnumerateRList[ MyExpand["groups.gv", FALSE].m, ExtractRegistry]; };
RETURN [ allRegistries ];
END; --AllRegistries--
FindLastPeriod: PROCEDURE[r: ROPE] RETURNS [lastPeriod: CARDINAL] =
BEGIN
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;
END; --FindLastPeriod--
ReportAllDown: PROCEDURE [dot: BOOLEAN, name: ROPE] =
BEGIN
IF dot
THEN outStr.PutRope["."]
ELSE outStr.PutF["\nAll down: %g. ", [rope[name]]];
END;
MyExpand: PROCEDURE [eName: ROPE, ignoreNotFound: BOOLEAN]
RETURNS [m: GVNames.RListHandle, c: CARDINAL, isSiteList: BOOLEAN] =
BEGIN
printDot: BOOLEANFALSE;
ReportNotFound: PROCEDURE =
{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;
END; --MyExpand--
MyGetFriends: PROCEDURE [eName: ROPE, ignoreNotFound: BOOLEAN]
RETURNS [m: GVNames.RListHandle, c: CARDINAL, isSiteList: BOOLEAN] =
BEGIN
printDot: BOOLEANFALSE;
ReportNotFound: PROCEDURE =
{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;
END;
ExtractRegistry: PROCEDURE [RName: ROPE] RETURNS [registry: ROPE] =
BEGIN
start: CARDINAL ← FindLastPeriod[RName]+1;
RETURN [IF start >= Rope.Length[RName]
THEN NIL ELSE Rope.Substr[RName, start, Rope.Length[RName] - start]]
END; --ExtractRegistry--
NameListToRope: PROCEDURE [mLH: GVNames.RListHandle] RETURNS [r: ROPE] =
BEGIN
AddMemberToRope: PROCEDURE[m: ROPE] RETURNS [done: BOOLEAN] =
BEGIN
IF r # NIL THEN r ← Rope.Cat[r, ", "];
r ← Rope.Cat[r, m];
done ← FALSE
END;
r ← NIL;
EnumerateRList[mLH, AddMemberToRope];
END; --NameListToRope--
ForWordsInRopeDo: PROCEDURE [r: ROPE, work: PROCEDURE[ROPE]] =
BEGIN
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;
END; -- ForWordsInRopeDo --
EnumerateRList: PROCEDURE [r: GVNames.RListHandle,
p: PROCEDURE [ROPE] RETURNS [BOOLEAN] ] =
{FOR r ← r, r.rest UNTIL r=NIL OR p[r.first] DO ENDLOOP};
ValidNameWithStar: PROCEDURE [reg: ROPE] RETURNS [ok: BOOL] =
BEGIN
printDot: BOOLEANFALSE;
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;
END;
CheckRegistryValidity: PROCEDURE [reg: ROPE] =
BEGIN
printDot: BOOLEANFALSE;
ReportInvalidRegistry: PROCEDURE =
BEGIN
outStr.PutF["%g%g\n\n", [rope[reg]], [rope[" is not a valid registry."]]];
ERROR inverterStopped;
END;
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 =>
BEGIN
name ← Rope.Cat[reg, ".foreign"];
SELECT GVNames.CheckStamp[name] FROM
group, notFound =>
ReportInvalidRegistry[];
individual =>
NULL;
allDown =>
{ReportAllDown[printDot, name]; printDot←TRUE; LOOP};
ENDCASE => ERROR;
END;
allDown =>
{ReportAllDown[printDot, name]; printDot←TRUE; LOOP};
ENDCASE => ERROR;
EXIT;
ENDLOOP;
END; --CheckRegistryValidity--
BadDL: TYPE = RECORD [name: ROPE, badMbr: LIST OF ROPE];
RecordBadMember: PROC [tbl: RedBlackTree.Table, dl, mbr: ROPE] =
BEGIN
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];
END; --RecordBadMember--
PrintBadMembers: PROC [tbl: RedBlackTree.Table, inputRegistries: ROPE] =
BEGIN
PrintBadDLsForRegistry: PROCEDURE [reg: ROPE] =
BEGIN
needRegistryLabel: BOOLEANTRUE;
acceptAll: BOOLEAN = 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
BEGIN
firstName: BOOLEANTRUE;
IF needRegistryLabel THEN BEGIN
IF needTitle THEN BEGIN
outStr.PutRope["\n\n\nDL's with members that are NOT REGISTERED."];
needTitle ← FALSE;
END;
outStr.PutF["\n\n\n""%g"" registry:\n", IO.rope[reg]];
needRegistryLabel ← FALSE;
END;
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];
END;
data ← RedBlackTree.LookupNextLarger[tbl, key];ENDLOOP;
END; --PrintBadDLsForRegistry--
needTitle: BOOLEANTRUE;
ForWordsInRopeDo[inputRegistries, PrintBadDLsForRegistry];
IF needTitle THEN outStr.PutRope["No bad members.\n"]
END; --PrintBadMembers--
Membership: TYPE = RECORD[PACKED SEQUENCE length: CARDINAL OF BOOLEAN];
MemberRecord: TYPE = RECORD[name: ROPE, knownToBeIndividual: BOOLEAN,
owner, friend, member: REF Membership];
GetKey: SAFE 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: SAFE PROC [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison] =
CHECKED BEGIN
a: ROPENARROW[k];
b: ROPENARROW[GetKey[data]];
RETURN [Rope.Compare[a, b, FALSE]]
END; --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 =
BEGIN
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];
END;
BuildUserInput: PROC =
BEGIN
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;
END;
ForceSelToFileName: Buttons.ButtonProc =
BEGIN
IF mouseButton#red
THEN ViewerTools.SetContents[fileName, defaultFileNamePattern]
ELSE ViewerTools.SetSelection[fileName];
END;
ForceSelToRegistries: Buttons.ButtonProc =
BEGIN
IF mouseButton#red
THEN ViewerTools.SetContents[registries, defaultRegistries]
ELSE ViewerTools.SetSelection[registries];
END;
BuildUserFeedback: PROC =
BEGIN
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;
END;
BuildExceptions: PROC =
BEGIN
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"];
END;
******************** Initialization ********************--
BuildOuter[];
END..