DIRECTORY Ascii USING[ Letter ], Atom USING [GetPName, MakeAtom], Buttons USING [ButtonProc], FS USING [Error], Commander USING[ CommandObject, CommandProc, Register ], CommandTool, Containers USING [ChildXBound], DB, Icons, IO, Menus USING [AppendMenuEntry, CreateMenu, Menu, MenuProc, CreateEntry], MessageWindow USING [Append, Confirm, Clear], Nut USING [Display, Edit, Query, PushDefaults], SquirrelDump USING [DumpToFile, LoadFromFile], NutOps USING [AtomFromSegment, SetUpSegment], NutViewer, Process, Rope, PrincOpsUtils USING [IsBound], UserProfile USING[Number, Token], ViewerEvents, ViewerOps, ViewerTools USING [GetContents, SetContents, SetSelection], ViewerIO USING [CreateViewerStreams], ViewerClasses; SquirrelToolImpl: CEDAR MONITOR IMPORTS Ascii, Atom, FS, Containers, CommandTool, DB, Icons, IO, MessageWindow, Menus, Nut, SquirrelDump, NutOps, NutViewer, Process, Rope, PrincOpsUtils, UserProfile, Commander, ViewerEvents, ViewerOps, ViewerTools, ViewerIO SHARES ViewerClasses = BEGIN OPEN IO; Viewer: TYPE = ViewerClasses.Viewer; ROPE: TYPE = Rope.ROPE; -- *********************************************** -- Initialization -- *********************************************** createSquirrelWindow: BOOL _ FALSE; openSquirrel: BOOL _ FALSE; squirrelSegment: PUBLIC ROPE; -- the name of any $Squirrel segment opened segmentName: ROPE; -- the name of the last segment opened with the Tool fileName: ROPE; -- the name of the last file opened with the Tool Initialize: PROCEDURE = TRUSTED { IF ~PrincOpsUtils.IsBound[DB.Initialize] THEN { err: ROPE; MessageWindow.Clear[]; MessageRope["Loading and starting Cypress... "]; err_ CommandTool.Run["Cypress"].errMsg; IF err.Length[]#0 THEN Message[err] ELSE Message["Done."]}; DB.Initialize[ nCachePages: UserProfile.Number["Squirrel.nCachePages", 256]]; NutViewer.stopped _ FALSE }; SquirrelProc: Commander.CommandProc = BEGIN segName: ROPE; r: ROPE; ch: CHAR; h: IO.STREAM _ IO.RIS[ cmd.commandLine ]; IF (r _ h.GetTokenRope[ ! IO.EndOfStream => {r _ NIL; CONTINUE}].token) # NIL THEN SELECT ch _ r.Fetch[0] FROM '[, '< => segName _ Rope.Concat[r, h.GetLineRope[]] ENDCASE => IF Ascii.Letter[ch] THEN segName _ Rope.Concat["[Local]", r]; SELECT TRUE FROM segName.Length[] # 0 => segmentName _ segName; ENDCASE => { segmentName _ UserProfile.Token["Squirrel.Segment", ""]; fileName _ UserProfile.Token["Squirrel.File", "[Local]Squirrel.segment"]; }; BuildSquirrel[]; IF segName # NIL THEN MyOpenProc[ NutViewer.squirrel ] -- user specified it, open it up END; -- *********************************************** -- Window and buttons -- *********************************************** squirrelIcon: Icons.IconFlavor _ tool; tsIn, tsOut: IO.STREAM _ NIL; segmentText: Viewer; -- the text argument for Segment fileText: Viewer; -- the text argument for File domainText: Viewer; -- the text argument for Domain nameText: Viewer; -- the text argument for Name StartUpMessage: ROPE _ "Squirrel 5.0 Release"; BuildSquirrel: PROC = { -- Builds and puts up the Squirrel window v: Viewer; typeScript: Viewer; info: ViewerClasses.ViewerRec_ [name: "Squirrel", iconic: TRUE, column: right, scrollable: FALSE, menu: squirrelMenu]; IF squirrelIcon = tool THEN squirrelIcon _ Icons.NewIconFromFile["Nut.icons", 0 ! FS.Error => {CONTINUE}]; IF squirrelIcon = tool THEN squirrelIcon _ Icons.NewIconFromFile["/Indigo/Squirrel/Icons/Nut.icons", 0 ! FS.Error => {CONTINUE}]; IF NutViewer.squirrel = NIL OR NutViewer.squirrel.destroyed THEN { info.icon_ squirrelIcon; NutViewer.squirrel _ ViewerOps.CreateViewer[flavor: $Container, info: info]; v _ BuildSquirrelArea[NutViewer.squirrel]; v _ NutViewer.MakeRuler[sib: v]; typeScript _ NutViewer.MakeTypescript[sib: v]; [tsIn, tsOut] _ ViewerIO.CreateViewerStreams[NIL, typeScript]; NutViewer.squirrelOut _ tsOut; ViewerOps.PaintViewer[NutViewer.squirrel, all]; squirrelEventReg_ ViewerEvents.RegisterEventProc[ proc: QuitProc, event: destroy, filter: NutViewer.squirrel]; ViewerOps.AddProp[NutViewer.squirrel, $Typescript, tsOut]; Message[StartUpMessage]; }; ViewerTools.SetContents[segmentText, segmentName]; ViewerTools.SetContents[fileText, fileName]; ViewerTools.SetContents[domainText, "Domain"]; ViewerTools.SetContents[nameText, "Domain"] }; BuildSquirrelArea: PROC [squirrel: Viewer] RETURNS [Viewer] = { tLabel: Viewer_ NutViewer.Initialize[squirrel]; tLabel _ NutViewer.MakeButton[ q: NIL, name: "Segment: ", proc: SegmentNameProc, border: FALSE, sib: tLabel]; segmentText _ NutViewer.NextRightTextViewer[sib: tLabel, w: squirrel.cw - tLabel.ww]; Containers.ChildXBound[segmentText.parent, segmentText]; tLabel _ NutViewer.MakeButton[ q: NIL, name: "File: ", proc: FileNameProc, border: FALSE, sib: tLabel, newLine: TRUE]; fileText _ NutViewer.NextRightTextViewer[sib: tLabel, w: squirrel.cw - tLabel.ww]; Containers.ChildXBound[fileText.parent, fileText]; tLabel _ NutViewer.MakeButton[ q: NIL, name: "Domain:", proc: DomainNameProc, border: FALSE, sib: tLabel, newLine: TRUE]; domainText _ NutViewer.NextRightTextViewer[sib: tLabel, w: squirrel.cw - tLabel.ww]; Containers.ChildXBound[domainText.parent, domainText]; tLabel _ NutViewer.MakeButton[q: NIL, name: "Name:", proc: NameNameProc, border: FALSE, sib: tLabel, newLine: TRUE]; nameText _ NutViewer.NextRightTextViewer[sib: tLabel, w: squirrel.cw - tLabel.ww]; Containers.ChildXBound[nameText.parent, nameText]; RETURN [nameText] }; DomainNameProc: Buttons.ButtonProc = { ViewerTools.SetSelection[domainText, NIL]}; NameNameProc: Buttons.ButtonProc = { ViewerTools.SetSelection[nameText, NIL]}; SegmentNameProc: Buttons.ButtonProc = { ViewerTools.SetSelection[segmentText, NIL]}; FileNameProc: Buttons.ButtonProc = { ViewerTools.SetSelection[fileText, NIL]}; DisplayerProc: Buttons.ButtonProc = { -- Display specified entity, opening segment if necessary physicalSegName: ROPE _ ViewerTools.GetContents[fileText]; domName: ROPE _ ViewerTools.GetContents[domainText]; entName: ROPE _ ViewerTools.GetContents[nameText]; seg: DB.Segment_ GetSegment[]; []_ NutOps.SetUpSegment[physicalSegName, seg]; DisplayEntity[domName, entName, seg]}; EditorProc: Buttons.ButtonProc = { -- Edit specified entity, opening segment if necessary physicalSegName: ROPE _ ViewerTools.GetContents[fileText]; domName: ROPE _ ViewerTools.GetContents[domainText]; entName: ROPE _ ViewerTools.GetContents[nameText]; seg: DB.Segment_ GetSegment[]; []_ NutOps.SetUpSegment[physicalSegName, seg]; EditEntity[domName, entName, seg]; }; QueryerProc: Buttons.ButtonProc = { domName: ROPE _ ViewerTools.GetContents[domainText]; entName: ROPE _ ViewerTools.GetContents[nameText]; -- Allow user to say domain foo, or just put foo in the domain field. IF domName.Equal["Domain"] THEN domName _ entName; IF domName.Length[]=0 THEN {Message["No domain specified!"]; RETURN}; QueryDomain[entName, domName, GetSegment[]] }; EraseDomains: PUBLIC PROC [dl: LIST OF DB.Domain] = { -- Erases all domains in dl, all their entities, and all relations that ref them. Careful. . . al: LIST OF DB.Attribute; FOR dlT: LIST OF DB.Domain _ dl, dlT.rest WHILE NOT (dlT = NIL) DO -- First destroy the relations that ref dlT.first (CedarDB would, but we want to tell user) IF (al _ DB.VL2EL[DB.GetPList[dlT.first, DB.aTypeOf]]) # NIL THEN {Message["Erasing Relations referencing ", DB.GetName[dlT.first], ":"]; EraseAttributesRelations[al]}; Message["Erasing Domain ", DB.GetName[dlT.first], ". . ."]; DB.DestroyDomain[dlT.first] ENDLOOP; }; EraseRelations: PUBLIC PROC [rl: LIST OF DB.Relation] = { -- Erases all relations in rl, and all their relships. Careful. . . FOR rlT: LIST OF DB.Relation _ rl, rlT.rest WHILE NOT (rlT = NIL) DO Message["Erasing Relation ", DB.GetName[rlT.first], ". . ."]; DB.DestroyRelation[rlT.first] ENDLOOP; }; EraseAttributesRelations: PROC [al: LIST OF DB.Attribute] = { -- Erases relations that attributes belong to OPEN DB; FOR alT: LIST OF Attribute _ al, alT.rest WHILE NOT (alT = NIL) DO IF NOT DB.Null[alT.first] THEN {r: DB.Relation _ V2E[GetP[alT.first, aRelationIs]]; Message["Erasing Relation ", DB.GetName[r], ". . ."]; DB.DestroyRelation[r]} ENDLOOP; }; GetSegment: PROC RETURNS [ATOM] = BEGIN segName: ROPE _ ViewerTools.GetContents[segmentText]; fileName: ROPE _ ViewerTools.GetContents[fileText]; IF Rope.Equal[segName, NIL] THEN -- user has not specified a segment to use, so extract it from the file RETURN[ NutOps.AtomFromSegment[fileName] ] ELSE -- user has specified a segment RETURN[Atom.MakeAtom[segName]]; END; squirrelMenu: Menus.Menu _ Menus.CreateMenu[2]; BuildSquirrelMenu: PROC = { OPEN Menus; AppendMenuEntry[ squirrelMenu, NutViewer.MakeMenuEntry[NutViewer.DBQueue[], "Save", MySaveProc]]; AppendMenuEntry[ squirrelMenu, NutViewer.MakeMenuEntry[q: NutViewer.DBQueue[], name: "Reset", proc: MyResetProc, guarded: TRUE]]; AppendMenuEntry[ squirrelMenu, NutViewer.MakeMenuEntry[NutViewer.DBQueue[], "Open", MyOpenProc]]; AppendMenuEntry[ squirrelMenu, NutViewer.MakeMenuEntry[NutViewer.DBQueue[], "Close", MyCloseProc]]; AppendMenuEntry[ -- don't want under Squirrel DBQueue so can do asynchronously squirrelMenu, Menus.CreateEntry["Load", MyLoadProc]]; AppendMenuEntry[ -- don't want under Squirrel DBQueue squirrelMenu, Menus.CreateEntry["Dump", MyDumpProc]]; AppendMenuEntry[ -- don't want under Squirrel DBQueue squirrelMenu, Menus.CreateEntry["List", ListSegsProc]]; AppendMenuEntry[squirrelMenu, NutViewer.MakeMenuEntry[ q: NutViewer.DBQueue[], name: "EraseSegment", proc: EraseAllProc, guarded: TRUE],]; AppendMenuEntry[squirrelMenu, NutViewer.MakeMenuEntry[ NutViewer.DBQueue[], "Display", DisplayerProc], 1]; AppendMenuEntry[squirrelMenu, NutViewer.MakeMenuEntry[ NutViewer.DBQueue[], "Edit", EditorProc], 1]; AppendMenuEntry[squirrelMenu, NutViewer.MakeMenuEntry[ NutViewer.DBQueue[], "Query", QueryerProc], 1]; AppendMenuEntry[squirrelMenu, NutViewer.MakeMenuEntry[ q: NutViewer.DBQueue[], name: "Erase", proc: MyEraseProc, guarded: TRUE], 1]; AppendMenuEntry[ squirrelMenu, Menus.CreateEntry["Stop!", MyStopProc], 1]; AppendMenuEntry[ squirrelMenu, NutViewer.MakeMenuEntry[NIL, "Debug", DebugProc], 1]; }; -- *********************************************** -- Menu items -- *********************************************** MySaveProc: Menus.MenuProc = { MessageRope["Saving ... "]; -- sometimes takes a while, so tell him before DB.MarkTransaction[DB.TransactionOf[GetSegment[]]]; Message[Atom.GetPName[GetSegment[]], " transaction committed."] }; MyResetProc: Menus.MenuProc = { s: DB.Segment = GetSegment[]; fileName: ROPE = ViewerTools.GetContents[fileText]; DB.AbortTransaction[DB.TransactionOf[s]]; Message[Atom.GetPName[s], " transaction aborted."]; DB.OpenTransaction[ s ]; Message[Atom.GetPName[s], " transaction opened."] }; MyCloseProc: Menus.MenuProc = { s: DB.Segment = GetSegment[]; fileName: ROPE = ViewerTools.GetContents[fileText]; DB.CloseTransaction[DB.TransactionOf[s]]; Message[Atom.GetPName[s], " segment has been closed"] }; MyOpenProc: Menus.MenuProc = { success: BOOL; s: DB.Segment = GetSegment[]; fileName: ROPE _ ViewerTools.GetContents[fileText]; oldName: ROPE = DB.GetSegmentInfo[s].filePath; open: BOOL = DB.TransactionOf[s] # NIL; switch: CHAR; sameFile, readOnly: BOOL; [fileName, switch]_ ExtractSwitch[fileName]; readOnly_ switch='r OR switch='R; -- See whether the segment is already open with a different file name IF Rope.Fetch[fileName, 0] # '[ THEN fileName _ Rope.Concat["[Local]", fileName]; IF Rope.Find[fileName, ".segment"] = -1 THEN fileName _ Rope.Concat[fileName, ".segment"]; sameFile _ Rope.Equal[fileName, oldName]; IF NOT sameFile AND open THEN { Message[oldName, " must be closed first!"]; RETURN }; IF sameFile AND open THEN { Message[oldName, " already open!"]; RETURN }; -- File is either different or previous one was closed; must and can open segment [success, readOnly]_ NutOps.SetUpSegment[fileName, s,, readOnly]; IF success THEN { Message[ fileName, " has been opened", IF readOnly THEN ", read-only" ELSE ""]} ELSE Message["Can't open transaction on ", fileName, "!"]; }; DebugProc: Menus.MenuProc = BEGIN Nut.PushDefaults[domain: ViewerTools.GetContents[domainText], segment: GetSegment[]]; END; EraseAllProc: Menus.MenuProc = { s: DB.Segment = GetSegment[]; fileName: ROPE = ViewerTools.GetContents[fileText]; IF NOT NutOps.SetUpSegment[fileName, s].success THEN RETURN; DB.EraseSegment[s]; DB.OpenTransaction[s]; Message[fileName, " has been erased and re-initialized"] }; ListSegsProc: Menus.MenuProc = { segs: LIST OF DB.Segment = DB.GetSegments[]; trans: DB.Transaction; filePath: ROPE; readOnly: BOOL; IF segs=NIL THEN { Message["No declared segments"]; RETURN}; MessageRope["\nDeclared segments:"]; FOR s1: LIST OF DB.Segment_ segs, s1.rest UNTIL s1=NIL DO MessageRope["\n "]; MessageRope[Atom.GetPName[s1.first]]; [filePath,, trans, readOnly]_ DB.GetSegmentInfo[s1.first]; MessageRope[ Rope.Cat[": ", filePath] ]; IF trans#NIL THEN IF readOnly THEN MessageRope[" (Open read-only)"] ELSE MessageRope[" (Open)"]; ENDLOOP; Message[""]; }; MyEraseProc: Menus.MenuProc = { domain: ROPE = ViewerTools.GetContents[domainText]; IF domain.Equal["Domain", FALSE] THEN MyDomainEraseProc[] ELSE IF domain.Equal["Relation", FALSE] THEN MyRelationEraseProc[] ELSE { ENABLE DB.Error => {Message["Can't find entity!"]; CONTINUE}; entityToDelete: ROPE = ViewerTools.GetContents[nameText]; DB.DestroyEntity[DB.FetchEntity[ DB.DeclareDomain[domain, GetSegment[], OldOnly], entityToDelete]]; Message[entityToDelete, " erased."]}; }; MyDomainEraseProc: PROC = { domainsToDelete: ROPE = ViewerTools.GetContents[nameText]; NutViewer.stopped_ FALSE; EraseDomains[NameListToEntityList [RopeToNameList[domainsToDelete], DB.DomainDomain, GetSegment[]]]; Message["Do Save to commit deletions."] }; MyRelationEraseProc: PROC = { relationsToDelete: ROPE = ViewerTools.GetContents[nameText]; NutViewer.stopped_ FALSE; EraseRelations[NameListToEntityList [RopeToNameList[relationsToDelete], DB.RelationDomain, GetSegment[]]]; Message["Do Save to commit deletions."] }; MyDumpProc: Menus.MenuProc = { segment: ROPE = Atom.GetPName[ GetSegment[] ]; NutViewer.stopped _ FALSE; DumpData[segment]; }; MyStopProc: Menus.MenuProc = { NutViewer.stopped _ TRUE }; squirrelEventReg: ViewerEvents.EventRegistration_ NIL; QuitProc: ViewerEvents.EventProc = { IF squirrelEventReg = NIL THEN RETURN[FALSE]; TRUSTED {Process.Detach[ FORK DoQuit[] ]}; RETURN[TRUE] }; DoQuit: PROC = { s: DB.Segment = GetSegment[]; fileName: ROPE = ViewerTools.GetContents[fileText]; trans: DB.Transaction = DB.TransactionOf[s]; ViewerEvents.UnRegisterEventProc[squirrelEventReg, destroy]; squirrelEventReg_ NIL; IF trans # NIL THEN { IF MessageWindow.Confirm[prompt: Rope.Cat["Close ", fileName, " first?"]] THEN { DB.CloseTransaction[trans] } }; ViewerOps.DestroyViewer[NutViewer.squirrel]; NutViewer.squirrel _ NIL; NutViewer.squirrelOut _ IO.noWhereStream }; MyLoadProc: Menus.MenuProc = { segment: ROPE = Atom.GetPName[ GetSegment[] ]; NutViewer.stopped _ FALSE; SetPriority[]; SquirrelDump.LoadFromFile[Rope.Cat[ segment, ".dump" ], ViewerTools.GetContents[fileText]]; }; -- *********************************************** -- Support procedures -- *********************************************** WhiteSpace: IO.BreakProc = { RETURN[ IF char = IO.SP OR char = IO.CR THEN IO.CharClass[break] ELSE IO.CharClass[other] ] }; DumpData: PROCEDURE[command: ROPE] = -- Command = segment [fileName _ ] [~] [!] [[Domains:] aaa bbb ccc] [Relations: rrr sss ttt] BEGIN token: ROPE; fileName: ROPE; dl: LIST OF DB.Domain; rl: LIST OF DB.Relation; file: BOOLEAN _ TRUE; domains: BOOLEAN _ TRUE; complement: BOOLEAN _ FALSE; entityCentric: BOOLEAN _ FALSE; stream: IO.STREAM _ IO.RIS[command]; segName: ROPE = stream.GetTokenRope[].token; seg: DB.Segment = Atom.MakeAtom[segName]; IF DB.TransactionOf[seg]=NIL THEN {Message["Segment not open!"]; RETURN}; SetPriority[]; BEGIN IF command.Find["_"] = -1 THEN { file _ FALSE; fileName _ Rope.Cat[segName, ".dump"] }; WHILE ~stream.EndOf[] DO [] _ stream.SkipWhitespace[]; token _ stream.GetTokenRope[WhiteSpace ! IO.EndOfStream => {token _ NIL; CONTINUE}].token; IF file THEN {fileName _ token; file _ FALSE; LOOP}; IF token = NIL THEN EXIT; SELECT TRUE FROM token.Equal["Domain", FALSE] => NULL; token.Equal["Relation", FALSE] => NULL; token.Equal["Domains:", FALSE] => domains _ TRUE; token.Equal["Relations:", FALSE] => domains _ FALSE; token.Equal["~"] => complement _ TRUE; token.Equal["_"] => NULL; token.Equal["!"] => entityCentric_ TRUE; ENDCASE => IF domains THEN { domain: DB.Domain = DB.DeclareDomain[token, seg, OldOnly]; IF domain=NIL THEN GO TO NotFound ELSE dl _ CONS[domain, dl] } ELSE { relation: DB.Relation = DB.DeclareRelation[token, seg, OldOnly]; IF relation=NIL THEN GO TO NotFound ELSE rl _ CONS[relation, rl] }; ENDLOOP; IF dl = NIL AND rl = NIL THEN complement _ TRUE; SquirrelDump.DumpToFile[segName, fileName, dl, rl, complement, entityCentric]; EXITS NotFound => IF domains THEN Message[token, " not a domain. Dump aborted."] ELSE Message[token, " not a relation. Dump aborted."]; END END; NameListToEntityList: PROC [nl: LIST OF ROPE, d: DB.Domain, seg: DB.Segment] RETURNS [el: LIST OF DB.Entity] = { -- Turns a list of names into a list of entities. seg only used if system domain. OPEN DB; e: Entity; IF nl = NIL THEN RETURN [NIL]; e _ FetchEntity[d, nl.first, seg]; IF e = NIL THEN {Message[nl.first, " is not a ", GetName[d]]; RETURN [NameListToEntityList[nl.rest, d, seg]]} ELSE RETURN [CONS[e, NameListToEntityList[nl.rest, d, seg]]] }; RopeToNameList: PROC [s: ROPE] RETURNS [nl: LIST OF ROPE] = { -- Takes rope with ","s or " "s in it and breaks up into components name: ROPE; begin, end: INT; IF s.Length[] = 0 THEN RETURN [NIL]; begin _ s.SkipOver[0, ", "]; -- skip any leading blanks or commas IF begin = s.Length[] THEN RETURN [NIL]; -- whole string was blank end _ s.SkipTo[begin, ", "]; -- find next blank or comma after that name _ s.Substr[begin, end - begin]; -- collect string between them RETURN [CONS[name, RopeToNameList[s.Substr[end]]]] }; Message: PUBLIC SAFE PROC [msg1, msg2, msg3, msg4: ROPE _ NIL] = -- Put CR at beginning if MessageWindow, at end if going to SquirrelTool {NutViewer.Message[NutViewer.squirrel, msg1, msg2, msg3, msg4]}; MessageRope: PUBLIC SAFE PROC [msg: ROPE] = { IF NutViewer.squirrel=NIL THEN MessageWindow.Append[msg] ELSE tsOut.PutRope[msg]; }; -- *********************************************** -- User executive commands -- *********************************************** ShowEntityProc: Commander.CommandProc = -- Read line of the form "DBDisplay Segment: DomainName: EntityName". -- Entity name is everything after second ": " and up to CR. BEGIN ENABLE IO.EndOfStream => {Message[ "Illegal command syntax: expect DBDisplay [Segment:] [Domain:] Entity"]; CONTINUE}; h: IO.STREAM = IO.RIS[cmd.commandLine]; segName, domName, entName: ROPE; segName _ h.GetTokenRope[].token; IF h.PeekChar[]#': THEN { -- Both segment and domain were defaulted: search ALL domains in Squirrel segment! d: DB.Domain; ds: DB.EntitySet_ DB.DomainSubset[d: DB.DomainDomain, searchSegment: $Squirrel]; entName_ Rope.Cat[segName, h.GetLineRope[]]; UNTIL DB.Null[d_ DB.NextEntity[ds]] DO IF DB.FetchEntity[d, entName]#NIL THEN {DisplayEntity[DB.NameOf[d], entName, $Squirrel]; RETURN}; ENDLOOP; Message[entName, " not found in any domain!"]; RETURN }; domName_ h.GetTokenRope[].token; IF h.PeekChar[]#': THEN { -- Segment was defaulted, since no domain was given: search the Squirrel segment entName_ Rope.Cat[domName, h.GetLineRope[]]; domName_ segName; segName_ "Squirrel" } ELSE { [] _ h.GetChar[]; []_ h.SkipWhitespace[]; -- Skip over the ":" and following blanks entName _ h.GetLineRope[] }; DisplayEntity[domName, entName, Atom.MakeAtom[segName]]; END; OpenProc: Commander.CommandProc = { h: IO.STREAM _ IO.RIS[cmd.commandLine]; segName: ROPE = h.GetTokenRope[IO.IDProc].token; s: DB.Segment = NutOps.AtomFromSegment[segName]; []_ NutOps.SetUpSegment[segName, s] }; EraseProc: Commander.CommandProc = { h: IO.STREAM _ IO.RIS[cmd.commandLine]; segName: ROPE = h.GetTokenRope[ ].token; s: DB.Segment = NutOps.AtomFromSegment[ segName ]; IF NOT NutOps.SetUpSegment[segName, s].success THEN RETURN; IF DB.TransactionOf[s]#NIL THEN DB.CloseTransaction[DB.TransactionOf[s]]; DB.EraseSegment[s]; DB.OpenTransaction[s] }; DumpProc: Commander.CommandProc = { NutViewer.stopped_ FALSE; DumpData[cmd.commandLine]}; LoadProc: Commander.CommandProc = { ENABLE IO.EndOfStream => {Message[ "Illegal command syntax: expect DBLoad Filename SegmentAtom"]; CONTINUE}; h: IO.STREAM = IO.RIS[cmd.commandLine]; fileName: ROPE = h.GetTokenRope[].token; DBName: ROPE = h.GetTokenRope[].token; SetPriority[]; SquirrelDump.LoadFromFile[ IF fileName = NIL THEN "DB.dump" ELSE fileName, IF DBName = NIL THEN segmentName ELSE DBName ] }; -- *********************************************** -- Entity manipulation -- *********************************************** DisplayEntity: PROC[domain, name: ROPE, segment: DB.Segment] = { -- Tries to display an entity with name entName in domain domName in segment segment dom: DB.Domain; ent: DB.Entity; enl: INT; IF NOT IsOpen[segment] THEN RETURN; -- Make special case for DomainDomain and RelationDomain IF domain.Equal["Domain", FALSE] THEN IF name.Equal["Domain", FALSE] THEN {Nut.Display[e: DB.DomainDomain, eName: name, d: DB.FetchEntity[DB.DomainDomain, domain, segment], seg: segment, newV: NutViewer.OneViewer[e: DB.DomainDomain, eName: name, d: DB.FetchEntity[DB.DomainDomain, domain, segment], seg: segment]]; RETURN} ELSE IF name.Equal["Relation", FALSE] THEN {Nut.Display[e: DB.RelationDomain, eName: name, d: DB.FetchEntity[DB.DomainDomain, domain, segment], seg: segment, newV: NutViewer.OneViewer[e: DB.DomainDomain, eName: name, d: DB.FetchEntity[DB.DomainDomain, domain, segment], seg: segment]]; RETURN}; dom_ DB.FetchEntity[DB.DomainDomain, domain, segment]; IF dom = NIL THEN {Message[domain, " is not a domain."]; RETURN}; enl_ name.Length[]; IF enl#0 AND name.Fetch[enl-1]='* THEN -- Interpret "*" as a wild card if at the end and not in debug mode BEGIN es: DB.EntitySet_ DB.DomainSubset[dom, name.Substr[0, enl-1], name.Substr[0, enl-1].Cat["\177"], First, TRUE, segment]; count: INT_ 0; UNTIL (ent_ DB.NextEntity[es])=NIL DO count_ count+1; IF count>5 THEN {Message["... more than 5; others not displayed"]; EXIT}; Nut.Display[e: ent, d: dom, seg: segment, eName: name, newV: NutViewer.OneViewer[e: ent, eName: name, d: dom, seg: segment]]; ENDLOOP; IF count=0 THEN Message["No such entity"]; END ELSE BEGIN ent _ DB.FetchEntity[dom, name, segment]; IF ent=NIL THEN {Message[name, " does not exist in domain ", domain]; RETURN}; IF DB.Null[ent] THEN Message["No such entity"] ELSE Nut.Display[e: ent, d: dom, seg: segment, eName: name, newV: NutViewer.OneViewer[e: ent, eName: name, d: dom, seg: segment]]; END; }; IsOpen: PROC[ seg: DB.Segment ] RETURNS[ open: BOOLEAN ] = { open _ FALSE; FOR sl: LIST OF DB.Segment _ DB.GetSegments[], sl.rest UNTIL sl = NIL DO IF sl.first = seg THEN { open _ TRUE; RETURN } ENDLOOP; Message[ Atom.GetPName[seg], " segment not open" ] }; EditEntity: PROC[domain, name: ROPE, segment: DB.Segment] = { -- Again, first check to see that the segment is open IF NOT IsOpen[segment] THEN RETURN ELSE { dom: DB.Domain_ DB.FetchEntity[DB.DomainDomain, domain, segment]; IF dom=NIL THEN Message["No such domain."] ELSE Nut.Edit[eName: name, e: DB.FetchEntity[dom, name, segment], d: dom, seg: segment] } }; QueryDomain: PROC[entity, domain: ROPE, segment: DB.Segment] = { -- Again, first check to see that the segment is open IF NOT IsOpen[segment] THEN RETURN ELSE { dom: DB.Domain_ DB.FetchEntity[DB.DomainDomain, domain, segment]; ent: DB.Entity _ DB.FetchEntity[DB.DomainDomain, entity, segment]; IF dom=NIL THEN Message["No such domain."] ELSE Nut.Query[eName: entity, e: ent, d: dom, seg: segment] } }; ExtractSwitch: PROC[old: ROPE] RETURNS [new: ROPE, switch: CHAR] = -- Extracts one-character switch, returns blank if none. BEGIN switchesPos: INT_ Rope.Find[old, "/"]; switch_ ' ; new_ old; IF switchesPos#-1 THEN { switch_ new.Fetch[switchesPos+1]; new_ Rope.Concat[new.Substr[0, switchesPos], new.Substr[switchesPos+2]]; }; END; SetPriority: PROC = TRUSTED { Process.SetPriority[Process.priorityBackground] }; -- *********************************************** -- Start code -- *********************************************** BuildSquirrelMenu[]; Commander.Register[ "Squirrel", SquirrelProc, "Database application tool"]; Commander.Register[ "DBDisplay", ShowEntityProc, "Displays a database entity"]; Commander.Register[ "DBDump", DumpProc, "segment [file _ ] [~] [!] [[Domains: ] aaa bbb] [Relations: rrr sss]"]; Commander.Register[ "DBLoad", LoadProc, "Loads given dump file (Squirrel.dump default) into given segment"]; Commander.Register[ "DBEraseSegment", EraseProc, "Erases a database segment"]; Commander.Register[ "DBOpen", OpenProc, "Open a database segment file"]; Initialize[]; END. CHANGE LOG: Butler, June 26, 1984: Made many changes to comply with new organization of Squirrel Butler, July 3, 1984: Added "File:" Button to squirrelTool. This distinguishes between the physical segment (File) and the logical segment (Segment). ¸File: SquirrelToolImpl.mesa -- Last edited by -- Maxwell on: September 7, 1982 2:52 pm -- Willie-Sue on: February 22, 1983 4:24 pm -- Cattell on: September 16, 1983 4:08 pm -- Donahue on: July 26, 1983 9:50 am -- Widom on: June 18, 1984 9:38:11 am PDT -- Butler on: July 3, 1984 11:34:45 am PDT -- *********************************************** -- Building the menu -- *********************************************** Ê ¼˜Jšœ³™³JšDœÏk œ œœ!œœœœFœœœ œNœ!œ6œ&œRœœ>œ7œ=œœœœœ œÄœœœœœœœœÏcx˜™ Jšœœœ˜#Jšœœœ˜Jšœœœž+˜JJšœ œž4˜HJš`œ œž1œÏn œ œœœœ œœŠœœœœdœ Ïbœœœ œœ œœœœœœœœ œœ œœHœœœ+œœœ<œ½œ œœ"ž!œœž~œ;œœœž ˜„ Jšžœž˜3JšIœž œžœœŸ œœ ž*œfœ"œœœ?œ œœœVœ œœœœœ¾œ­Ÿœœœsœ:œÚœ4œœÄœ7œœ¿œ4œœ›œ˜ÇJšÆ œBœ œ@œ œCœ œ@œ œž:œœ3œ6œ/œy  œž7œœ3œ6œ/œ}  œ&œ6œ*žFœœœœœ#œ?Ÿ œœœœœœž`œœœœœœœœœœœœ ž\œœœœœœœ8œkœ(œ"œŸœœœœœœžEœœœœœœœœœ'œ(œ$œŸœœœœœž.œœœœœœœœœœ œœœœœYœ$œœ ˜ôš œŸ œœœœ˜"šœ˜Jšœ5˜5Jšœ3˜3šœ ˜ JšœG˜GJšœ$˜*—šœ$˜$Jšœ˜—J˜——Jšœ˜Jšž|™|Jšœ1˜1J•StartOfExpansion[prompt: ROPE _ NIL]špŸœœœòœçž>œLž%œKž%œÅœÊœ‘œžœžvœ  œ3ž/œœœg  œœ$œ'œœJœO  œœ$œ'œœO  œ!œ œ'œ3œœ'œœœœœKœžFœœœ2œ&œbœœ œœ5œœ œœ-œžRœJœ œ˜Ñš œ/œ œœ œE  œ˜Áš˜JšœU˜UJšœ˜——Jšœ  œœ&œ)œœ*œœœœU  œœœœ œœœ œœœœ$œ*œœœœœœœ_œHœœœœ œ&œœ  œ œ+œœœœœœœœœœ*œœ+œœœvÐbnœœœ<œRœS¡œœœ=œVœW  œ!œ9œ  œ)œ;œ  œœœœœœœœœœ ¡œœ œ$œ.œœdœœ œœœOœœfœœ  œ!œ9œ}ž~œ œœœœœœœœœœœœŸœ œ œž^œœ œœ œœœœœœœœœœœœœœœœœœœ)œ'œœœœ œœœœœ/œœdœœœœœœœ œ œœœ œœœ!œœ$œœ$œœ&œœ-œ œ/œ œœ œœ œ5œœœœœ œœœœ œ7œ œœœœ œœœœœœœœœYœœ œ8œ8œœ Ÿœœ œœœœœ œœœœžSœœœœœœœœ0œœ œDœ2œ œœ7Ÿœœœœœœœ žDœ œœœœœœ%ž%œœœœœžœ!ž'œ)žœœœ2Ÿœœœœœœ žIœKŸ œœœœœ œœœœ!ž‚œŸœžFœž=œœœœiœ œœœœ2œ,œœ žSœ œœ œœcœœ œœ œœœœœ!œ œ=œ3œœ žQœfœ3ž*œeœ œ#œœœœ œœœ^  œ#œœœœ œ#œ2œœ)œœœœœœœœœœ œ3œ' œ œœ_œ œœœœ!œ'œWœ œœ œœ œœ œ œž~œŸ œœœ œžVœ œœœœœœœž9œœœœœœœœOœ œ}œFœ œbœœœœœœQœ œ|œFœ œaœ œ œ%œœœ(œœœ žCœœ œ œ\œœ œœœœ#œ œ4œ©œœ œ"œœœœ(œœœ>œ œœœ$œ£œ Ÿœœœ œœœœœœœ œœœœœœ œœœ<Ÿ œœœ œž6œœœœœœ œ œ œ)œœœ#œ"œAŸ œœœ œž6œœœœœœ œ œ œ.œ œ œ(œœœ$œ>¡ œœœœœ œž;œœœ3œœ†œŸ œœœ:žvœÅœœœï˜Ét—…—nJ}¾