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: BOOL ← FALSE;
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: BOOL ← FALSE;
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: BOOL ← FALSE;
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: BOOL ← FALSE;
allRegistries: ROPE ← NIL;
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: BOOL ← FALSE;
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: BOOL ← FALSE;
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: BOOL ← FALSE;
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];
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: BOOL ← FALSE;
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: BOOL ← FALSE;
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: BOOL ← TRUE;
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: BOOL ← TRUE;
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: BOOL ← TRUE;
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: ROPE ← NARROW[k];
b: ROPE ← NARROW[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[];
}..