initial source import
diff --git a/doc/tools/findacks b/doc/tools/findacks
new file mode 100755
index 0000000..c13b00f
--- /dev/null
+++ b/doc/tools/findacks
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+"""Script to locate email addresses in the CVS logs."""
+__version__ = '$Revision: 1.1.1.1 $'
+
+import os
+import re
+import sys
+import UserDict
+
+import cvsinfo
+
+
+class Acknowledgements(UserDict.UserDict):
+    def add(self, email, name, path):
+        d = self.data
+        d.setdefault(email, {})[path] = name
+
+
+def open_cvs_log(info, paths=None):
+    cvsroot = info.get_cvsroot()
+    cmd = "cvs -q -d%s log " % cvsroot
+    if paths:
+        cmd += " ".join(paths)
+    return os.popen(cmd, "r")
+
+
+email_rx = re.compile("<([a-z][-a-z0-9._]*@[-a-z0-9.]+)>", re.IGNORECASE)
+
+def find_acks(f, acks):
+    prev = ''
+    filename = None
+    MAGIC_WORDS = ('van', 'von')
+    while 1:
+        line = f.readline()
+        if not line:
+            break
+        if line.startswith("Working file: "):
+            filename = line.split(None, 2)[2].strip()
+            prev = line
+            continue
+        m = email_rx.search(line)
+        if m:
+            words = prev.split() + line[:m.start()].split()
+            L = []
+            while words \
+                  and (words[-1][0].isupper() or words[-1] in MAGIC_WORDS):
+                L.insert(0, words.pop())
+            name = " ".join(L)
+            email = m.group(1).lower()
+            acks.add(email, name, filename)
+        prev = line
+
+
+def load_cvs_log_acks(acks, args):
+    repolist = cvsinfo.get_repository_list(args or [""])
+    for info, paths in repolist:
+        print >>sys.stderr, "Repository:", info.get_cvsroot()
+        f = open_cvs_log(info, paths)
+        find_acks(f, acks)
+        f.close()
+
+
+def load_tex_source_acks(acks, args):
+    for path in args:
+        path = path or os.curdir
+        if os.path.isfile(path):
+            read_acks_from_tex_file(acks, path)
+        else:
+            read_acks_from_tex_dir(acks, path)
+
+
+def read_acks_from_tex_file(acks, path):
+    f = open(path)
+    while 1:
+        line = f.readline()
+        if not line:
+            break
+        if line.startswith(r"\sectionauthor{"):
+            line = line[len(r"\sectionauthor"):]
+            name, line = extract_tex_group(line)
+            email, line = extract_tex_group(line)
+            acks.add(email, name, path)
+
+
+def read_acks_from_tex_dir(acks, path):
+    stack = [path]
+    while stack:
+        p = stack.pop()
+        for n in os.listdir(p):
+            n = os.path.join(p, n)
+            if os.path.isdir(n):
+                stack.insert(0, n)
+            elif os.path.normpath(n).endswith(".tex"):
+                read_acks_from_tex_file(acks, n)
+
+
+def extract_tex_group(s):
+    c = 0
+    for i in range(len(s)):
+        if s[i] == '{':
+            c += 1
+        elif s[i] == '}':
+            c -= 1
+            if c == 0:
+                return s[1:i], s[i+1:]
+
+
+def print_acks(acks):
+    first = 1
+    for email, D in acks.items():
+        if first:
+            first = 0
+        else:
+            print
+        L = D.items()
+        L.sort()
+        prefname = L[0][1]
+        for file, name in L[1:]:
+            if name != prefname:
+                prefname = ""
+                break
+        if prefname:
+            print prefname, "<%s>:" % email
+        else:
+            print email + ":"
+        for file, name in L:
+            if name == prefname:
+                print "    " + file
+            else:
+                print "    %s (as %s)" % (file, name)
+
+
+def print_ack_names(acks):
+    names = []
+    for email, D in acks.items():
+        L = D.items()
+        L.sort()
+        prefname = L[0][1]
+        for file, name in L[1:]:
+            prefname = prefname or name
+        names.append(prefname or email)
+    def f(s1, s2):
+        s1 = s1.lower()
+        s2 = s2.lower()
+        return cmp((s1.split()[-1], s1),
+                   (s2.split()[-1], s2))
+    names.sort(f)
+    for name in names:
+        print name
+
+
+def main():
+    args = sys.argv[1:]
+    acks = Acknowledgements()
+    load_cvs_log_acks(acks, args)
+    load_tex_source_acks(acks, args)
+    print_ack_names(acks)
+
+
+if __name__ == "__main__":
+    main()