Added a new script in common/ "cleanup_unref.py" which removes all
parameterized cell layouts from a directory that are unreferenced
by any other layout file.  These "orphan" cells are commonly left
behind when changing parameter values of parameterized cells.
diff --git a/common/cleanup_unref.py b/common/cleanup_unref.py
new file mode 100755
index 0000000..23f1805
--- /dev/null
+++ b/common/cleanup_unref.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+#
+# cleanup_unref.py:  Look up all .mag files in the indicated path, and
+# parse all files for "use" lines and make a list of all the cells being
+# used.  Next, check all files to determine which ones are parameterized
+# PDK cells (those that have "string gencell" in the properties section).
+# Finally, remove all the files which represent parametersized PDK cells
+# that are not used anywhere by any other layout file.
+#
+# The purpose of this script is to reduce the number of cells scattered
+# about the filesystem that come from parameterized cells being modified
+# in place.  Eventually, magic will be upgraded to have a way to indicate
+# just the cell name and parameters in the .mag file so that all parameterized
+# cells can be generated on-the-fly and do not need to be saved in .mag files.
+# 
+# Note that this routine assumes that all files are local to a single project
+# directory and are not being used by layout in some other directory.  So use
+# with caution.
+#
+# Usage, e.g.:
+#
+# cleanup_unref.py <path_to_layout>
+
+import os
+import re
+import sys
+import glob
+
+def usage():
+    print("cleanup_unref.py [-remove] <path_to_layout>")
+    return 0
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    optionlist = []
+    arguments = []
+
+    testmode = True
+    debugmode = False
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) != 1:
+        print("Wrong number of arguments given to cleanup_unref.py.")
+        usage()
+        sys.exit(0)
+
+    if '-remove' in optionlist or '-delete' in optionlist:
+        testmode = False
+    if '-debug' in optionlist:
+        debugmode = True
+
+    filepath = arguments[0]
+
+    magpath = filepath + '/*.mag'
+    sourcefiles = glob.glob(magpath)
+
+    if len(sourcefiles) == 0:
+        print("Warning:  No files were found in the path " + filepath + ".")
+
+    usedfiles = []
+    pdkfiles = []
+
+    for file in sourcefiles:
+        if debugmode:
+            print("Checking file " + file)
+        fileroot = os.path.split(file)[1]
+        cellname = os.path.splitext(fileroot)[0]
+
+        proprex = re.compile('^string[ \t]+gencell[ \t]+([^ \t]+)')
+        userex = re.compile('^use[ \t]+([^ \t]+)')
+
+        with open(file, 'r') as ifile:
+            magtext = ifile.read().splitlines() 
+            for line in magtext:
+                pmatch = proprex.match(line)
+                if pmatch:
+                    pdkfiles.append(cellname)
+                umatch = userex.match(line)
+                if umatch:
+                    cellname = umatch.group(1)
+                    if cellname not in usedfiles:
+                        usedfiles.append(cellname)
+
+    unusedfiles = list(item for item in pdkfiles if item not in usedfiles)
+
+    if debugmode:
+        print('')
+        print('Parameterized cells found:')
+        for cellname in sorted(pdkfiles):
+            print(cellname)
+
+        print('')
+        print('Used cells found:')
+        for cellname in sorted(usedfiles):
+            print(cellname)
+    
+    if testmode:
+        # Just report on files that are unused
+        print('')
+        print('Parameterized cells not used by any layout:')
+        for cellname in sorted(unusedfiles):
+            print(cellname)
+    else:
+        # Remove files that are unused
+        for cellname in sorted(unusedfiles):
+            file = filepath + '/' + cellname + '.mag'
+            os.remove(file)
+            print('Removed unused parameterized cell ' + cellname)
+
+    print('')
+    print('Done!')