--- /dev/null
+
+"""
+*** RefCheck
+
+Flow
+ Read files
+ On @defManual manual refManual eg @defManual LM rlearning
+ Associate manual name 'manual' with reference @'refManual'{ ... }
+ Add 'refManual' to list of keywords
+ On @setManual manual set current manual name to 'manual'
+ On @include open and process new file
+ On @node add node to Nodes list with current manual name and current file name
+ On @ref add contents to References list with refManual, current manual name and current file name
+ On one of refManual keywords add contents to References list with ditto
+ Match refs and nodes
+ Process References list:
+ Check reference is contained in Nodes list with refManual in Nodes = refManual in References
+ Print results
+
+Known issues
+ Node names containing commas are only checked up to the comma
+ Spurious warnings "Xref should be internal" for files in /included
+
+"""
+
+
+##################################################
+class CrossRefs:
+ """ Holds References and Nodes """
+ def __init__(self):
+ self.Manuals = {}
+ self.Nodes = {}
+ self.nodeNames = {} # used to check for duplicates only
+ self.Refs = []
+ self.nodeCount = 0
+
+ def addManual(self, manualName, refManual):
+ self.Manuals[refManual] = manualName
+
+ def getRefManuals(self):
+ return self.Manuals.keys()
+
+ def getManualName(self, refManual):
+ return self.Manuals[refManual]
+
+ def addNode(self, nodeName, manualName, fileName):
+ global returnCode
+# print "Node: ", nodeName, " in ", manualName, " found in ", fileName
+ if manualName+"/"+nodeName in self.Nodes.keys():
+ print "Error: Duplicate nodename ",nodeName, " in ", fileName, " and ", self.Nodes[manualName+"/"+nodeName][1]
+ returnCode=1
+ self.Nodes[manualName + "/" + nodeName] = [manualName, fileName]
+ self.nodeNames[nodeName] = fileName
+
+ def addRef(self, toManualName, toHeading, inFileName):
+# if inFileName == "notation/vocal.itely":
+# print "Ref to ", toManualName, "/",toHeading, " found in ", inFileName
+ self.Refs.append([toManualName + "/" + toHeading, inFileName])
+
+ def check(self):
+ noErrors = True
+ for [refHeading, refFileName] in self.Refs:
+ try:
+ targetFileName = self.Nodes[refHeading]
+# if refFileName == "notation/vocal.itely":
+# print "ref to: ", refHeading, " in ", refFileName, " found in ", targetFileName
+ except KeyError:
+ noErrors = False
+ print "ref to: ", refHeading, " in ", refFileName, " not found"
+ if noErrors:
+ print " All references satisfied"
+ else:
+ returnCode=1
+
+##################################################
+class File:
+ """ Process an included file """
+
+ # Class variables
+ CurrentManualName = ""
+ DefaultPath = ""
+ Excludes = []
+ Paths = {}
+
+ # Methods
+ def __init__(self, fileName):
+ self.fileName = fileName
+ try:
+ self.fullFileName = File.Paths[fileName] + fileName
+ except KeyError:
+ self.fullFileName = File.DefaultPath + fileName
+
+ def read(self, crossRefs):
+ """ Process File """
+
+ skip = False
+ try:
+ myfile = open(self.fullFileName, 'r')
+ except IOError:
+ print "File ", self.fullFileName, " referenced in ", File.CurrentManualName, " but not found"
+ return
+ remainderLine = ""
+ lineNo = 0
+ for line in myfile:
+ lineNo += 1
+ words = line.split()
+ if len(words) > 0:
+ if words[0] == "@ignore" or words[0] == "@macro":
+ skip = True
+ if skip and len(words) > 1:
+ if words[0] == "@end" and (words[1].find("ignore") >= 0 or words[1].find("macro") >= 0):
+ skip = False
+
+ if not skip and words[0] != "@c":
+ if words[0].find("@defManual") >= 0:
+ # Manual definition found - extract manual name and refManual string
+ manualName = words[1]
+ refManual = words[2]
+ crossRefs.addManual(manualName, refManual)
+# print manualName, refManual
+
+ elif words[0].find("@defaultPath") >=0:
+ File.DefaultPath = words[1]
+
+ elif words[0].find("@path") >=0:
+ File.Paths[words[1]] = words[2]
+
+ elif words[0].find("@setManual") >= 0:
+ File.CurrentManualName = words[1]
+# print " Checking ", File.CurrentManualName
+
+ elif words[0].find("@exclude") >=0:
+ File.Excludes.append(words[1])
+
+ elif words[0].find("@include") >= 0:
+ if words[1] not in File.Excludes:
+ currentFileName = words[1]
+# print " File: ", currentFileName
+ currentFile = File(currentFileName)
+ currentFile.read(crossRefs)
+
+ elif words[0] == "@node":
+ nodeName = line[6:-1]
+ crossRefs.addNode(nodeName, File.CurrentManualName, self.fileName)
+
+ # Find references
+
+ twoLines = remainderLine + ' ' + line.strip()
+ manualRefStrings = crossRefs.getRefManuals()
+ refFound = False
+ for manualRefString in manualRefStrings:
+ toManualName = crossRefs.getManualName(manualRefString)
+ actualToManualName = toManualName
+ if toManualName == "this":
+ toManualName = File.CurrentManualName
+ refString = "@" + manualRefString + "{"
+ refStart = twoLines.find(refString)
+ if refStart >= 0:
+ refFound = True
+ if actualToManualName == File.CurrentManualName:
+ print "Warning: should xref be internal around line ", lineNo, " in ", self.fileName, "?"
+ twoLines = twoLines[refStart:]
+ refNodeStart = twoLines.find("{") + 1
+ # TODO Need to check here for nested {}
+ refNodeEnd = twoLines.find("}")
+ refNodeEndComma = twoLines.find(",")
+ if refNodeEndComma > 0:
+ refNodeEnd = min(refNodeEnd, refNodeEndComma)
+ if refNodeEnd >= 0:
+ crossRefs.addRef(toManualName, twoLines[refNodeStart:refNodeEnd], self.fileName)
+ remainderLine=twoLines[refNodeEnd+1:]
+ if refFound:
+ refFound = False
+ break
+ if not refFound:
+ remainderLine = ""
+
+ myfile.close()
+ return
+
+topFile = File("scripts/auxiliar/ref_check.tely") # TODO get from input params
+print "RefCheck ver 0.1"
+returnCode=0
+crossRefs = CrossRefs()
+topFile.read(crossRefs)
+crossRefs.check()
+if returnCode > 0:
+ print "Errors found: status code: ",returnCode
\ No newline at end of file