DIRECTORY Atom USING [MakeAtom, GetPName], Commander, CommandTool, DBTools, FS, Booting USING [CheckpointProc, RegisterProcs, RollbackProc], Convert USING[RopeFromRope], DB, IO, IOClasses, TextFind, MessageWindow USING [Append], Process USING[Ticks, SecondsToTicks, Detach, Pause], Rope USING [Cat, Equal, Substr, ROPE, Length, Concat], UserProfile USING [Token, ProfileChangedProc, CallWhenProfileChanges], UserCredentials USING[CredentialsChangeProc], ViewerClasses ; DBToolsImpl: CEDAR MONITOR IMPORTS Atom, Booting, CommandTool, Convert, FS, IO, IOClasses, MessageWindow, Process, Rope, DB, TextFind, UserProfile EXPORTS DBTools = BEGIN OPEN DB, IO, Rope; ROPE: TYPE = Rope.ROPE; toolDomain: DB.Domain; -- the domain of tools loadFileProp: [0..6) = 0; -- the .load file for the tool docFileProp: [0..6) = 1; -- the documentation file for the tool briefDocProp: [0..6) = 2; -- a brief description of the tool viewerFlavorProp: [0..6) = 3; -- the registered viewer flavor for the tool namePatternProp: [0..6) = 4; -- the name pattern for the tool argumentPatternProp: [0..6) = 5; -- the argument pattern for the tool PropertyRecord: TYPE = RECORD[name: ROPE, prop: DB.Attribute _ NIL]; propertyTable: ARRAY[0..6) OF PropertyRecord _ [[name: "LoadFile"], [name: "DocFile"], [name: "BriefDoc"], [name: "ViewerFlavor"], [name: "NamePattern"], [name: "ArgumentPattern"]]; -- a list consisting of all of the properties given above flavorRelation: DB.Relation; -- the relation corresponding to the flavor property flavorOf: DB.Attribute; -- the "of" attribute of the flavor relation (the "is" attribute is the viewerFlavorProp) descriptorRelation: DB.Relation; -- the description of tools descriptorOf: DB.Attribute; -- a tool descriptorIs: DB.Attribute; -- is a ROPE ToolDB: PUBLIC ROPE _ NIL; pendingChange: BOOL _ FALSE; -- this is set by the rollback and credentials change procs to remember a potential change of state; it is checked by CarefullyApply, which will call ResetSchema if it is true toolTrans: DB.Transaction _ NIL; readOnly: PUBLIC BOOLEAN _ TRUE; -- true if the segment is readonly activity: BOOLEAN _ FALSE; -- true if a database operation has been performed recently ticksToWait: Process.Ticks _ Process.SecondsToTicks[60]; transOpened: CONDITION; LoadError: ERROR = CODE; loadedList: LIST OF ROPE _ NIL; -- a list of all of the loads performed EstablishToolDB: PUBLIC ENTRY PROC [file: Rope.ROPE _ NIL] = { ENABLE UNWIND => NULL; ToolDB _ IF file = NIL THEN UserProfile.Token[key: "Tool.Segment", default: "[Luther.Alpine]Tool.Segment"] ELSE file; pendingChange _ TRUE }; WatchDBActivity: PROC[] = { WHILE TRUE DO Process.Pause[ticksToWait]; CheckConnection[] ENDLOOP }; CheckConnection: ENTRY PROC[] = { ENABLE UNWIND => NULL; IF NOT activity THEN { CloseTransaction[]; -- don't keep the connection open too long WAIT transOpened }; activity _ FALSE; }; Close: PUBLIC ENTRY PROC [] = { CloseTransaction[] }; CloseTransaction: INTERNAL PROC [] = { caughtAborted: BOOL _ FALSE; IF toolTrans # NIL THEN DB.CloseTransaction[toolTrans ! DB.Aborted => { caughtAborted _ TRUE; CONTINUE }]; IF caughtAborted THEN DB.AbortTransaction[toolTrans]; toolTrans _ NIL }; RegisterTool: PUBLIC ENTRY PROC [toolName, loadFile: ROPE] ~ { ENABLE UNWIND => NULL; IF InternalRegisterTool[toolName: toolName, loadFile: loadFile] THEN DB.MarkTransaction[toolTrans] ELSE MessageWindow.Append["Can not register tool."]}; InternalRegisterTool: INTERNAL PROC[toolName: ROPE, loadFile, docFile, briefDoc: ROPE _ NIL, descriptors: LIST OF ROPE _ NIL] RETURNS[success: BOOLEAN] = { ENABLE UNWIND => NULL; DoRegisterTool: PROC[] = { toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName]; IF loadFile # NIL THEN [] _ SetP[toolEntity, propertyTable[loadFileProp].prop, S2V[loadFile]]; IF docFile # NIL THEN [] _ SetP[toolEntity, propertyTable[docFileProp].prop, S2V[docFile]]; IF briefDoc # NIL THEN [] _ SetP[toolEntity, propertyTable[briefDocProp].prop, S2V[briefDoc]]; IF descriptors = NIL THEN RETURN; BEGIN toolAttrValue: DB.AttributeValue = [descriptorOf, toolEntity]; oldrships: RelshipSet = RelationSubset[descriptorRelation, LIST[toolAttrValue]]; FOR old: DB.Relship _ NextRelship[oldrships], NextRelship[oldrships] UNTIL old = NIL DO DB.DestroyRelship[old] ENDLOOP; DB.ReleaseRelshipSet[oldrships]; FOR ds: LIST OF ROPE _ descriptors, ds.rest WHILE ds # NIL DO newDescrValue: DB.AttributeValue = [descriptorIs, S2V[descriptors.first]]; [] _ DeclareRelship[descriptorRelation, LIST[toolAttrValue, newDescrValue]] ENDLOOP END }; IF readOnly OR ToolDB = NIL OR toolName = NIL THEN { IF readOnly THEN MessageWindow.Append["File is read only."] ELSE IF ToolDB = NIL THEN MessageWindow.Append["ToolDB is NIL."] ELSE MessageWindow.Append["toolName is NIL."]; RETURN; -- nothing to do }; success _ CarefullyApply[DoRegisterTool] }; GetLoadFile: PUBLIC ENTRY PROC [toolName: ROPE] RETURNS [loadFile: ROPE] ~ { ENABLE UNWIND => NULL; [loadFile ~ loadFile] _ InternalGetToolProps[toolName] }; InternalGetToolProps: INTERNAL PROC [toolName: ROPE] RETURNS [loadFile, docFile, briefDoc: ROPE] ~ { ENABLE UNWIND => NULL; DoGetToolInfo: PROC[] = { toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName]; toolAttrValue: DB.AttributeValue = [descriptorOf, toolEntity]; IF toolEntity = NIL THEN RETURN; loadFile _ V2S[GetP[toolEntity, propertyTable[loadFileProp].prop]]; docFile _ V2S[GetP[toolEntity, propertyTable[docFileProp].prop]]; briefDoc _ V2S[GetP[toolEntity, propertyTable[briefDocProp].prop]] }; IF NOT CarefullyApply[DoGetToolInfo] THEN RETURN[NIL, NIL, NIL] }; GetToolDocumentation: PUBLIC ENTRY PROC [toolName: ROPE] RETURNS [docFile, briefDoc: ROPE] ~ { ENABLE UNWIND => NULL; [docFile ~ docFile, briefDoc ~ briefDoc] _ InternalGetToolProps[toolName] }; SetToolDocumentation: PUBLIC ENTRY PROC [toolName: ROPE, docFile, briefDoc: ROPE _ NIL] ~ { ENABLE UNWIND => NULL; IF InternalRegisterTool[toolName: toolName, docFile: docFile, briefDoc: briefDoc] THEN DB.MarkTransaction[toolTrans] }; SetToolDescriptors: PUBLIC ENTRY PROC[toolName: ROPE, descriptors: LIST OF ROPE _ NIL] = { ENABLE UNWIND => NULL; DoSetDescriptors: PROC[] = { toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName]; IF descriptors = NIL THEN RETURN; BEGIN toolAttrValue: DB.AttributeValue = [descriptorOf, toolEntity]; oldrships: RelshipSet = RelationSubset[descriptorRelation, LIST[toolAttrValue]]; FOR old: DB.Relship _ NextRelship[oldrships], NextRelship[oldrships] UNTIL old = NIL DO DB.DestroyRelship[old] ENDLOOP; DB.ReleaseRelshipSet[oldrships]; FOR ds: LIST OF ROPE _ descriptors, ds.rest WHILE ds # NIL DO newDescrValue: DB.AttributeValue = [descriptorIs, S2V[ds.first]]; [] _ DeclareRelship[descriptorRelation, LIST[toolAttrValue, newDescrValue]] ENDLOOP END }; IF readOnly OR ToolDB = NIL OR toolName = NIL THEN RETURN; -- nothing to do IF CarefullyApply[DoSetDescriptors] THEN DB.MarkTransaction[toolTrans] }; GetToolDescriptors: PUBLIC ENTRY PROC[toolName: ROPE] RETURNS[descriptors: LIST OF ROPE] = { DoGetToolDescriptors: PROC[] = { toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName]; toolAttrValue: DB.AttributeValue = [descriptorOf, toolEntity]; IF toolEntity = NIL THEN RETURN; BEGIN toolAttrValue: DB.AttributeValue = [descriptorOf, toolEntity]; rships: RelshipSet = RelationSubset[descriptorRelation, LIST[toolAttrValue]]; FOR old: DB.Relship _ NextRelship[rships], NextRelship[rships] UNTIL old = NIL DO descriptors _ CONS[V2S[DB.GetF[old, descriptorIs]], descriptors] ENDLOOP; DB.ReleaseRelshipSet[rships]; END }; IF NOT CarefullyApply[DoGetToolDescriptors] THEN RETURN[NIL] }; FindMatchingTools: PUBLIC ENTRY PROC [descriptors: LIST OF ROPE] RETURNS [tools: LIST OF ROPE] ~ { ENABLE UNWIND => NULL; DoFindMatch: PROC[] = { entityList, newList: LIST OF DB.Entity _ NIL; descriptorList: LIST OF DB.AttributeValue _ NIL; rshipSet: DB.RelshipSet; IF descriptors = NIL THEN { -- produce the list of all of the tools in the database toolList: LIST OF DB.Entity = DB.EntitySetToList[DB.DomainSubset[toolDomain]]; FOR tl: LIST OF DB.Entity _ toolList, tl.rest UNTIL tl = NIL DO tools _ CONS[DB.NameOf[tl.first], tools] ENDLOOP; RETURN }; FOR desc: LIST OF ROPE _ descriptors, desc.rest UNTIL desc = NIL DO descriptorList _ CONS[AttributeValue[descriptorIs, S2V[desc.first]], descriptorList] ENDLOOP; rshipSet _ RelationSubset[ descriptorRelation, LIST[descriptorList.first]]; descriptorList _ descriptorList.rest; FOR rs: DB.Relship _ NextRelship[rshipSet], NextRelship[rshipSet] UNTIL rs = NIL DO entityList _ CONS[V2E[GetF[rs, descriptorIs]], entityList] ENDLOOP; ReleaseRelshipSet[rshipSet]; FOR desc: LIST OF ROPE _ descriptors, desc.rest UNTIL desc = NIL DO descrAttrValue: DB.AttributeValue = [descriptorIs, desc.first]; FOR eL: LIST OF DB.Entity _ entityList, eL.rest UNTIL eL = NIL DO toolAttrValue: DB.AttributeValue = [descriptorOf, eL.first]; IF DeclareRelship[descriptorRelation, LIST[toolAttrValue, descrAttrValue], OldOnly] # NIL THEN newList _ CONS[eL.first, newList] ENDLOOP; entityList _ newList; newList _ NIL ENDLOOP; FOR eL: LIST OF Entity _ entityList, eL.rest UNTIL eL = NIL DO tools _ CONS[DB.NameOf[eL.first], tools] ENDLOOP }; IF NOT CarefullyApply[DoFindMatch] THEN RETURN[NIL] }; InternalLoadTool: INTERNAL PROC [toolName: ROPE, errorStream: IO.STREAM _ IO.noWhereStream] ~ { loadFile: ROPE = InternalGetToolProps[toolName].loadFile; command: ROPE; IF loadFile = NIL THEN RETURN; command _ Rope.Cat["Source ///Commands/", loadFile, "\n"]; InternalDoLoad[toolName, command, errorStream]; }; InternalDoLoad: INTERNAL PROC[toolName, commandLine: ROPE, errorStream: IO.STREAM _ IO.noWhereStream] = { DoCommand[commandLine, errorStream]; InternalAddLoaded[toolName] }; LoadTool: PUBLIC ENTRY PROC [toolName: ROPE, errorStream: IO.STREAM _ IO.noWhereStream] ~ { ENABLE UNWIND => NULL; IF NOT CheckLoaded[toolName] THEN InternalLoadTool[toolName, errorStream] }; AddLoaded: ENTRY PROC [tool: ROPE] ~ { InternalAddLoaded[tool] }; InternalAddLoaded: INTERNAL PROC [tool: ROPE] ~ { loadedList _ CONS[tool, loadedList] }; CheckLoaded: PROC [tool: ROPE] RETURNS [yes: BOOLEAN] ~ { yes _ FALSE; FOR loaded: LIST OF ROPE _ loadedList, loaded.rest UNTIL loaded = NIL DO IF Rope.Equal[loaded.first, tool] THEN RETURN[TRUE] ENDLOOP }; ApplyTool: PUBLIC ENTRY PROC [toolName, arguments: ROPE, errorStream: IO.STREAM _ IO.noWhereStream] ~ { loadFile: ROPE = InternalGetToolProps[toolName].loadFile; command: ROPE; IF Rope.Equal[loadFile, ""] AND DB.DeclareEntity[toolDomain, toolName, OldOnly] = NIL THEN RETURN; -- if these are true, then the tool isn't even registered (it may not have a load file if the tools is part of LifeSupport) IF NOT Rope.Equal[loadFile, ""] THEN { -- load the .load file from ///Commands InternalLoadTool[toolName, errorStream]; command _ Rope.Concat["///Commands/", toolName] } ELSE command _ toolName; IF arguments # NIL THEN command _ Rope.Cat[command, " ", arguments, "\n"] ELSE command _ Rope.Concat[command, "\n"]; TRUSTED {Process.Detach[ FORK DoCommand[command, errorStream] ] } }; DoCommand: PROC[commandLine: ROPE, errorStream: IO.STREAM _ IO.noWhereStream] = { cmdHandle: Commander.Handle = NEW[Commander.CommandObject _ []]; cmdHandle.err _ errorStream; cmdHandle.out _ IO.noWhereStream; [] _ CommandTool.DoCommandRope[commandLine: commandLine, parent: cmdHandle] }; RegisterViewerFlavor: PUBLIC ENTRY PROC [tool: ROPE, flavor: ViewerClasses.ViewerFlavor] ~ { ENABLE UNWIND => NULL; DoRegisterViewerFlavor: PROC = { toolEntity: DB.Entity = DeclareEntity[toolDomain, tool, OldOnly]; atomName: Rope.ROPE = IF flavor = NIL THEN NIL ELSE Atom.GetPName[flavor]; IF toolEntity = NIL THEN RETURN; [] _ SetP[toolEntity, propertyTable[viewerFlavorProp].prop, S2V[atomName]] }; IF CarefullyApply[DoRegisterViewerFlavor] THEN DB.MarkTransaction[toolTrans] }; RegisterNamePattern: PUBLIC ENTRY PROC [toolName: ROPE, pattern: ROPE] ~ { ENABLE UNWIND => NULL; DoRegisterNamePattern: PROC = { toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName, OldOnly]; IF toolEntity = NIL THEN RETURN; [] _ SetP[toolEntity, propertyTable[namePatternProp].prop, S2V[pattern]] }; IF CarefullyApply[DoRegisterNamePattern] THEN DB.MarkTransaction[toolTrans] }; RegisterArgumentPattern: PUBLIC ENTRY PROC [toolName: ROPE, pattern: ROPE] ~ { ENABLE UNWIND => NULL; DoRegisterArgumentPattern: PROC = { toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName, OldOnly]; IF toolEntity = NIL THEN RETURN; [] _ SetP[toolEntity, propertyTable[argumentPatternProp].prop, S2V[pattern]] }; IF CarefullyApply[DoRegisterArgumentPattern] THEN DB.MarkTransaction[toolTrans] }; GetViewerInfo: PUBLIC ENTRY PROC [toolName: ROPE] RETURNS [flavor: ViewerClasses.ViewerFlavor, namePattern, argumentPattern: ROPE] ~ { ENABLE UNWIND => NULL; [flavor, namePattern, argumentPattern] _ InternalGetViewerInfo[toolName] }; InternalGetViewerInfo: INTERNAL PROC [toolName: ROPE] RETURNS [flavor: ViewerClasses.ViewerFlavor, namePattern, argumentPattern: ROPE] ~ { ENABLE UNWIND => NULL; DoGetToolInfo: PROC[] = { toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName]; IF toolEntity = NIL THEN RETURN; flavor _ Atom.MakeAtom[V2S[GetP[toolEntity, propertyTable[viewerFlavorProp].prop]]]; namePattern _ V2S[GetP[toolEntity, propertyTable[namePatternProp].prop]]; argumentPattern _ V2S[GetP[toolEntity, propertyTable[argumentPatternProp].prop]] }; IF NOT CarefullyApply[DoGetToolInfo] THEN RETURN[NIL, NIL, NIL] }; ViewerToTool: PUBLIC ENTRY PROC [v: ViewerClasses.Viewer] RETURNS [toolName: ROPE, arguments: ROPE] ~ { ENABLE UNWIND => NULL; DoViewerTool: PROC = { viewerName: ROPE = v.name; flavor: ROPE = Atom.GetPName[v.class.flavor]; flavorAttrValue: DB.AttributeValue = [propertyTable[viewerFlavorProp].prop, S2V[flavor]]; toolSet: DB.RelshipSet = RelationSubset[flavorRelation, LIST[flavorAttrValue]]; toolRelation: DB.Relship _ NextRelship[toolSet]; toolEntity: DB.Entity _ IF toolRelation = NIL THEN NIL ELSE V2E[GetF[toolRelation, flavorOf]]; ReleaseRelshipSet[toolSet]; IF toolEntity = NIL THEN BEGIN toolSet: DB.EntitySet = DomainSubset[toolDomain]; FOR tool: DB.Entity _ NextEntity[toolSet], NextEntity[toolSet] UNTIL tool = NIL DO namePattern: ROPE = V2S[GetP[tool, propertyTable[namePatternProp].prop]]; pattern: TextFind.Finder = TextFind.CreateFromRope[namePattern]; found: BOOLEAN; after, before: TextFind.Offset; [found ~ found, after ~ after, before ~ before] _ TextFind.SearchRope[pattern, viewerName]; IF found AND (before = 0) AND (after = viewerName.Length[]) THEN {toolEntity _ tool; EXIT} ENDLOOP; ReleaseEntitySet[toolSet]; IF toolEntity = NIL THEN { toolName _ NIL; arguments _ NIL; RETURN } END; BEGIN argPattern: ROPE = V2S[GetP[toolEntity, propertyTable[argumentPatternProp].prop]]; pattern: TextFind.Finder = TextFind.CreateFromRope[argPattern]; found: BOOLEAN; at, atEnd: TextFind.Offset; [found ~ found, at ~ at, atEnd ~ atEnd] _ TextFind.SearchRope[pattern, viewerName]; IF found THEN arguments _ Rope.Substr[viewerName, at, atEnd-at]; toolName _ DB.NameOf[toolEntity] END }; IF NOT CarefullyApply[DoViewerTool] THEN RETURN[NIL, NIL] }; stream: IO.STREAM; -- the stream used either by Parse to read a catalogue or by WriteCatalogue to print one Parse: INTERNAL PROCEDURE[] = { ENABLE IO.EndOfStream, IO.Error => TRUSTED{ ERROR LoadError }; DO toolName: ROPE = IO.GetTokenRope[stream ! IO.EndOfStream => GOTO Done].token; toolEntity: DB.Entity = DeclareEntity[toolDomain, toolName]; ofValue: DB.AttributeValue = [descriptorOf, toolEntity]; FOR i: [0..6) IN [0..6) DO propertyName: Rope.ROPE = stream.GetID[]; propertyValue: Rope.ROPE = stream.GetRopeLiteral[]; FOR j: [0..6) IN [0..6) DO IF Rope.Equal[propertyTable[j].name, propertyName] THEN {[] _ DB.SetP[toolEntity, propertyTable[j].prop, S2V[propertyValue]]; EXIT} ENDLOOP; ENDLOOP; IF NOT Rope.Equal[stream.GetTokenRope[].token, "("] THEN ERROR LoadError; DO token: ROPE; token _ IO.GetCedarTokenRope[stream].token; IF Rope.Equal[token,")"] THEN EXIT; [] _ DeclareRelship[descriptorRelation, LIST[ofValue, AttributeValue[descriptorIs, S2V[token]]]] ENDLOOP ENDLOOP; EXITS Done => stream.Close[]; }; InternalWrite: INTERNAL PROC[] = { tools: DB.EntitySet = DB.DomainSubset[toolDomain]; FOR tool: DB.Entity _ NextEntity[tools], NextEntity[tools] UNTIL tool = NIL DO OPEN IO; stream.PutF["\n %g", rope[DB.NameOf[tool]]]; FOR i: [0..6) IN [0..6) DO stream.PutF["\n %g %g ", rope[propertyTable[i].name], rope[Convert.RopeFromRope[V2S[GetP[tool, propertyTable[i].prop]]]]] ENDLOOP; BEGIN descrAttrValue: DB.AttributeValue = [descriptorOf, tool]; descRships: DB.RelshipSet = DB.RelationSubset[descriptorRelation, LIST[descrAttrValue]]; stream.Put[rope[" ( "]]; FOR descr: DB.Relship _ NextRelship[descRships], NextRelship[descRships] UNTIL descr = NIL DO descriptor: ROPE = V2S[GetF[descr, descriptorIs]]; stream.PutF[" %g", rope[Convert.RopeFromRope[descriptor]]] ENDLOOP; stream.Put[rope[" ) "]]; DB.ReleaseRelshipSet[descRships] END ENDLOOP; stream.Close[] }; WriteCatalogue: PUBLIC ENTRY PROC [file: Rope.ROPE] = { ENABLE UNWIND => NULL; stream _ FS.StreamOpen[file, $append ! FS.Error => { MessageWindow.Append[error.explanation]; stream _ NIL; CONTINUE}]; IF stream # NIL THEN [] _ CarefullyApply[InternalWrite] }; OpenUp: Booting.RollbackProc = { DB.Initialize[nCachePages: 256] }; CloseTrans: ENTRY Booting.CheckpointProc = { CloseTransaction[] }; NewUserReset: ENTRY UserCredentials.CredentialsChangeProc = { CloseTransaction[] }; ProfileChangeReset: ENTRY UserProfile.ProfileChangedProc = { newToolDB: ROPE = UserProfile.Token[key: "Tool.Segment", default: "[Luther.Alpine]Tool.segment"]; IF NOT Rope.Equal[ToolDB, newToolDB] THEN { ToolDB _ newToolDB; pendingChange _ TRUE } }; ResetSchema: INTERNAL PROC[changingDBs: BOOL] = { IF pendingChange THEN CloseTransaction[]; IF toolTrans # NIL THEN RETURN; IF NOT SetUpSegment[] THEN RETURN; IF NOT DB.Null[toolDomain] THEN RETURN; -- all is well, don't bother recomputing schema toolDomain _ DeclareDomain["Tool", $Tool]; FOR i: [0..6) IN [0..6) DO propertyTable[i].prop _ DeclareProperty[relationName: propertyTable[i].name, of: toolDomain, is: RopeType, segment: $Tool] ENDLOOP; flavorRelation _ V2E[GetP[propertyTable[viewerFlavorProp].prop, aRelationIs, aRelationOf]]; flavorOf _ DB.DeclareAttribute[r: flavorRelation, name: "of", version: OldOnly]; descriptorRelation _ DeclareRelation[name: "Descriptor", segment: $Tool]; descriptorOf _ DeclareAttribute[r: descriptorRelation, name: "of", type: toolDomain]; descriptorIs _ DeclareAttribute[r: descriptorRelation, name: "is", type: RopeType]; toolTrans _ DB.TransactionOf[$Tool] }; ReadCatalogue: PUBLIC ENTRY PROC[file: Rope.ROPE] = TRUSTED { ENABLE BEGIN UNWIND => NULL; LoadError => GOTO Failure; END; stream _ FS.StreamOpen[file ! FS.Error => {stream _ NIL; CONTINUE}]; IF stream = NIL THEN RETURN; stream _ IOClasses.CreateCommentFilterStream[stream]; DB.MarkTransaction[toolTrans]; IF CarefullyApply[Parse] THEN DB.MarkTransaction[toolTrans] ELSE DB.AbortTransaction[toolTrans] EXITS Failure => DB.AbortTransaction[toolTrans]; }; CarefullyApply: INTERNAL PROC [proc: PROC[]] RETURNS [succeeded: BOOL] ~ { ENABLE DB.Error, DB.Failure, DB.Aborted => {succeeded _ FALSE; GOTO Quit}; ResetSchema[changingDBs: pendingChange]; pendingChange _ FALSE; activity _ TRUE; succeeded _ TRUE; proc[ ! DB.Aborted => { succeeded _ FALSE; CONTINUE } ]; IF succeeded THEN RETURN; -- no aborted occurred DB.AbortTransaction[toolTrans]; toolTrans _ NIL; -- there isn't any transaction anymore ResetSchema[changingDBs: FALSE]; proc[]; -- don't bother trying to restart here -- succeeded _ TRUE; EXITS Quit => NULL; }; SetUpSegment: INTERNAL PROC[] RETURNS [success: BOOL] ~ { ENABLE DB.Aborted, DB.Failure, DB.Error => {success _ FALSE; CONTINUE}; segment: ATOM = $Tool; segmentNumber: NAT = 320B; readOnly _ FALSE; success _ TRUE; DB.Initialize[nCachePages: 256]; DB.DeclareSegment[ToolDB, segment, segmentNumber, FALSE]; DB.OpenTransaction[segment ! DB.Error => IF code = ProtectionViolation THEN {success _ FALSE; CONTINUE} ELSE REJECT ]; IF NOT success THEN { DB.CloseTransaction[DB.TransactionOf[segment]]; DB.DeclareSegment[ToolDB, segment, segmentNumber, TRUE, FALSE]; DB.OpenTransaction[segment]; success _ TRUE }; readOnly _ DB.GetSegmentInfo[segment].readOnly; toolTrans _ DB.GetSegmentInfo[segment].trans; NOTIFY transOpened -- start up the watch dog process again to try to shut it down }; TRUSTED { Booting.RegisterProcs[c: CloseTrans, r: OpenUp]; UserProfile.CallWhenProfileChanges[ProfileChangeReset]; EstablishToolDB[]; Process.Detach[ FORK WatchDBActivity[] ] }; END. |File: DBToolsImpl.mesa Last Edited by: Donahue, January 3, 1985 10:51:31 am PST (Simplified substantially to handle only those tools that are considered part of the current release) (Changed ticksToWait to 60 -- closes transactions more rapidly now) Last Edited by: Widom, August 22, 1984 11:20:36 am PDT Last Edited by: Winkler, May 24, 1985 11:48:55 am PDT Types Global variables for accessing the database Tools have the following properties (each property is a rope). What is given below are the indices into the propertyTable which contains the names and DB.Attributes for each of the properties Establishing the database Accessing Tools now set all of the descriptors for the tool first throw away all of the old ones now add the new ones first throw away all of the old ones now add the new ones compute the list of attribute/value pairs now, compute the list of entities matching the first descriptor reduce the list of entities by seeing which of them also have relationships with the remaining descriptors return the names of all of the entities remaining on the NewList Parsing Tool Catalogues Opening, closing segment, making/reading catalogue don't open up the new database yet; simply remember that it must be done if there is a pending change of databases, then reset things before trying the operation attempt to open for writing failed; open it for reading only Initialization Κr˜JšΟi™J™8J™eJ™CJ™6J™5J™šΟk ˜ Jšœžœ˜ J˜ J˜ J˜Jšžœ˜Jšœžœ/˜Jšžœžœžœ˜šœ žœžœž˜JšœYžœ˜c—J–Y[segmentFile: ROPE, seg: DB.Segment, number: NAT _ 0, makeReadOnly: BOOL _ FALSE]šœžœ˜J˜—š‘œžœ˜šžœžœž˜ Jšœ˜Jšœ˜Jšž˜—Jšœ˜J˜—š‘œžœžœ˜!Jšžœžœžœ˜šžœžœ žœ˜Jšœ *˜>Jšžœ˜—Jšœ žœ˜J˜—J˜Jš‘œž œžœ˜6J˜š‘œžœžœ˜&Jšœžœžœ˜šžœ žœž˜Jšžœžœžœžœ˜R—Jšžœžœžœ˜5Jšœ žœ˜——™š ‘ œžœžœžœžœ˜>Jšžœžœžœ˜šžœ>˜@Jšžœžœ˜#Jšžœ1˜5—J˜—š‘œžœžœ žœžœžœžœžœžœžœžœ žœ˜›Jšžœžœžœ˜š‘œžœ˜Jšœ žœ.˜<šžœ ž˜JšžœH˜L—šžœ ž˜JšžœF˜J—šžœ ž˜JšžœH˜L—Jšœ+™+Jšžœžœžœžœ˜!šž˜Jšœ$™$Jšœžœ-˜>Jšœ;žœ˜Pš žœžœ:žœžœž˜WJšžœ˜Jšžœ˜—Jšžœ˜ Jšœ™š žœžœžœžœžœžœž˜=Jšœžœ9˜JJšœ(žœ˜KJšž˜—Jšžœ˜——š žœ žœ žœžœ žœžœ˜4Jšžœ žœ+˜;š žœžœ žœžœ!žœ˜@Jšžœ#žœ˜.—Jšœžœ ˜J˜—Jšœ*˜*Jšœ˜—J˜š‘ œžœžœžœ žœžœ žœ˜LJšžœžœžœ˜Jšœ6˜6J˜J˜—š ‘œžœžœ žœžœžœ˜dJšžœžœžœ˜š‘ œžœ˜Jšœ žœ.˜Jšžœžœžœžœ˜ JšœC˜CJšœA˜AJšœE˜E—Jšžœžœžœžœžœžœžœ˜?J˜J˜—š‘œžœžœžœ žœžœžœ˜^Jšžœžœžœ˜JšœI˜IJ˜J˜—š‘œžœžœžœ žœžœžœ˜[Jšžœžœžœ˜JšžœPžœžœ˜tJ˜J˜—š‘œžœžœžœ žœžœžœžœžœ˜ZJšžœžœžœ˜š‘œžœ˜Jšœ žœ.˜Jšœ;žœ˜Pš žœžœ:žœžœž˜WJšžœ˜Jšžœ˜—Jšžœ˜ Jšœ™š žœžœžœžœžœžœž˜=Jšœžœ0˜AJšœ(žœ˜KJšž˜—Jšžœ˜—Jšžœ žœ žœžœ žœžœžœ ˜LJšžœ"žœžœ˜F—Jšœ˜J™—š‘œžœ žœžœžœžœžœ˜\š‘œžœ˜ Jšœ žœ.˜Jšžœžœžœžœ˜ šž˜Jšœžœ-˜>Jšœ8žœ˜Mš žœžœ4žœžœž˜QJšœžœžœ'˜@Jšžœ˜—Jšžœ˜Jšžœ˜——Jš žœžœ&žœžœžœ˜Jšœžœžœ˜(Jšžœ˜ ——Jš žœžœžœžœžœ˜3J˜J˜—š‘œžœžœ žœžœžœžœ˜_Jšœ žœ+˜9Jšœ žœ˜Jšžœ žœžœžœ˜Jšœ:˜:Jšœ/˜/J˜J˜—š ‘œž œžœžœžœžœ˜iJšœ$˜$Jšœ˜—J˜š‘œžœžœžœ žœžœžœžœ˜[Jšžœžœžœ˜Jšžœžœžœ(˜IJ˜J˜—Jš‘ œž œžœ ˜AJ˜Jš‘œž œžœžœ˜XJ˜š ‘ œžœžœžœžœ˜9Jšœžœ˜ š žœ žœžœžœžœ žœž˜HJšžœ žœžœžœ˜3Jšž˜—J˜J˜—š‘ œžœžœžœžœžœžœžœ˜gJšœ žœ+˜9Jšœ žœ˜Jš žœžœžœ0žœžœžœ {˜ήšžœžœžœ '˜NJšœ(˜(Jšœ1˜1—Jšžœ˜Jšžœ žœžœ2˜IJšžœ&˜*Jšžœžœ$˜AJšœ˜J˜—š ‘ œžœžœžœžœžœ˜QJšœžœ˜@Jšœ˜Jšœžœ˜!JšœN˜NJ˜—š ‘œžœžœžœžœ)˜\Jšžœžœžœ˜š‘œžœ˜ Jšœ žœ3˜AJš œžœžœ žœžœžœžœ˜JJšžœžœžœžœ˜ JšœM˜M—Jšžœ(žœžœ˜LJ˜J˜—š ‘œžœžœžœ žœ žœ˜JJšžœžœžœ˜š‘œžœ˜Jšœ žœ7˜EJšžœžœžœžœ˜ JšœK˜K—Jšžœ'žœžœ˜KJ˜J˜—š ‘œžœžœžœ žœ žœ˜NJšžœžœžœ˜š‘œžœ˜#Jšœ žœ7˜EJšžœžœžœžœ˜ JšœO˜O—Jšžœ+žœžœ˜OJ˜J˜—š‘ œžœžœžœ žœžœDžœ˜†Jšžœžœžœ˜JšœH˜HJ˜J˜—š ‘œžœžœ žœžœDžœ˜ŠJšžœžœžœ˜š‘ œžœ˜Jšœ žœ.˜šž˜Jš œ žœžœžœžœ ˜MJšœ žœ.˜žœ˜K—Jšžœ˜—Jšžœ˜—Jšžœžœ.žœžœ ˜Išž˜Jšœžœ˜ Jšœžœ!˜+Jšžœžœžœ˜#Jšœ(žœ4˜`Jšž˜—Jšžœ˜—šž˜Jšœ˜—Jšœ˜—J˜š‘ œžœžœ˜"Jšœžœ žœ˜2š žœžœ/žœžœž˜NJšžœžœ˜Jšœžœ˜,šžœ žœž˜Jšœ|˜|Jšžœ˜—šž˜Jšœžœ'˜9Jšœ žœžœ$žœ˜XJ˜š žœžœ<žœ žœž˜]Jšœ žœ"˜2Jšœ:˜:Jšžœ˜—Jšœ˜Jšžœ˜!Jšž˜—Jšžœ˜—J˜J˜—š ‘œžœžœžœ žœ˜7Jšžœžœžœ˜šœ žœžœ ˜4Jšœ(˜(Jšœ žœ˜Jšžœ˜ —Jšžœ žœžœ#˜7J˜——™2šœ žœ ˜CJ˜—Jšœ žœ2˜CJšœžœ@˜SJ˜šœžœ#˜˜QJ˜——šœ™šžœ˜ Jšœ0˜0Jšœ7˜7Jšœ˜Jšœžœ˜+—J˜J˜—Jšžœ˜—…—PΞpΌ