diff --git a/Mac/scripts/unweave.py b/Mac/scripts/unweave.py new file mode 100644 index 00000000000..8a5e80fcb7f --- /dev/null +++ b/Mac/scripts/unweave.py @@ -0,0 +1,164 @@ +"""An attempt at an unweave script. +Jack Jansen, jack@oratrix.com, 13-Dec-00 +""" +import re +import sys +import macfs +import os + +BEGINDEFINITION=re.compile("^<<(?P.*)>>=\s*") +USEDEFINITION=re.compile("^(?P
.*)<<(?P.*)>>[^=]")
+ENDDEFINITION=re.compile("^@")
+
+class Processor:
+	def __init__(self, filename):
+		self.items = {}
+		self.filename = filename
+		self.fp = open(filename)
+		self.lineno = 0
+		self.resolving = {}
+		self.resolved = {}
+		self.pushback = None
+		
+	def _readline(self):
+		"""Read a line. Allow for pushback"""
+		if self.pushback:
+			rv = self.pushback
+			self.pushback = None
+			return rv
+		self.lineno = self.lineno + 1
+		return self.fp.readline()
+		
+	def _linedirective(self):
+		"""Return a #line cpp directive for the current input file position"""
+		return '#line %d "%s"\n'%(self.lineno-2, os.path.split(self.filename)[1])
+		
+	def _readitem(self):
+		"""Read the definition of an item. Insert #line where needed. """
+		rv = [self._linedirective()]
+		while 1:
+			line = self._readline()
+			if not line:
+				break
+			if ENDDEFINITION.search(line):
+				break
+			if BEGINDEFINITION.match(line):
+				self.pushback = line
+				break
+			mo = USEDEFINITION.match(line)
+			if mo:
+				pre = mo.group('pre')
+				if pre:
+					rv.append(pre+'\n')
+			rv.append(line)
+			# For simplicity we add #line directives now, if
+			# needed.
+			if mo:
+				rv.append(self._linedirective())
+		return rv
+		
+	def _define(self, name, value):
+		"""Define an item, or append to an existing definition"""
+		if self.items.has_key(name):
+			self.items[name] = self.items[name] + value
+		else:
+			self.items[name] = value
+			
+	def read(self):
+		"""Read the source file and store all definitions"""
+		while 1:
+			line = self._readline()
+			if not line: break
+			mo = BEGINDEFINITION.search(line)
+			if mo:
+				name = mo.group('name')
+				value = self._readitem()
+				self._define(name, value)
+			else:
+				pass # We could output the TeX code but we don't bother.
+				
+	def resolve(self):
+		"""Resolve all references"""
+		for name in self.items.keys():
+			self._resolve_one(name)
+			
+	def _resolve_one(self, name):
+		"""Resolve references in one definition, recursively"""
+		# First check for unknown macros and recursive calls
+		if not self.items.has_key(name):
+			print "Undefined macro:", name
+			return ['<<%s>>'%name]
+		if self.resolving.has_key(name):
+			print "Recursive macro:", name
+			return ['<<%s>>'%name]
+		# Then check that we haven't handled this one before
+		if self.resolved.has_key(name):
+			return self.items[name]
+		# No rest for the wicked: we have work to do.
+		self.resolving[name] = 1
+		result = []
+		for line in self.items[name]:
+			mo = USEDEFINITION.search(line)
+			if mo:
+				# We replace the complete line. Is this correct?
+				macro = mo.group('name')
+				replacement = self._resolve_one(macro)
+				result = result + replacement
+			else:
+				result.append(line)
+		self.items[name] = result
+		self.resolved[name] = 1
+		del self.resolving[name]
+		return result
+		
+	def save(self, dir, pattern):
+		"""Save macros that match pattern to folder dir"""
+		# Compile the pattern, if needed
+		if type(pattern) == type(''):
+			pattern = re.compile(pattern)
+		# If the directory is relative it is relative to the sourcefile
+		if not os.path.isabs(dir):
+			sourcedir = os.path.split(self.filename)[0]
+			dir = os.path.join(sourcedir, dir)
+		for name in self.items.keys():
+			if pattern.search(name):
+				pathname = os.path.join(dir, name)
+				data = self._stripduplines(self.items[name])
+				self._dosave(pathname, data)
+				
+	def _stripduplines(self, data):
+		for i in range(len(data)-1, 0, -1):
+			if data[i][:5] == '#line' and data[i-1][:5] == '#line':
+				del data[i-1]
+		if data[-1][:5] == '#line':
+			del data[-1]
+		return data
+		
+	def _dosave(self, pathname, data):
+		"""Save data to pathname, unless it is identical to what is there"""
+		if os.path.exists(pathname):
+			olddata = open(pathname).readlines()
+			if olddata == data:
+				return
+		fp = open(pathname, "w").writelines(data)
+		
+def process(file):
+	pr = Processor(file)
+	pr.read()
+	pr.resolve()
+	pr.save(":jacktest:src", "^.*\.cp$")
+	pr.save(":jacktest:include", "^.*\.h")
+
+def main():
+	if len(sys.argv) > 1:
+		for file in sys.argv:
+			print "Processing", file
+			process(file)
+	else:
+		fss, ok = macfs.PromptGetFile("Select .nw source file", "TEXT")
+		if not ok:
+			sys.exit(0)
+		process(fss.as_pathname())
+		
+if __name__ == "__main__":
+	main()