New project: amalgamate /etc/services from little bits.
[services] / merge-services
diff --git a/merge-services b/merge-services
new file mode 100755 (executable)
index 0000000..2929bc8
--- /dev/null
@@ -0,0 +1,94 @@
+#! /usr/bin/python
+
+import sre as re
+import os
+from sys import argv, stderr
+
+class struct (object):
+  def __init__(me, **kw):
+    me.__dict__.update(kw)
+  def __repr__(me):
+    r = '%s(' % me.__class__.__name__
+    sep = ''
+    for k in me.__dict__:
+      r += sep + '%s=%r' % (k, me.__dict__[k])
+      sep = ', '
+    r += ')'
+    return r
+
+class service (struct):
+  def __str__(me):
+    return '%(name)s:%(port)d/%(proto)s' % me.__dict__
+  def key(me):
+    return me.port, me.proto, me.name
+  def parse(string):
+    m = re.match(r'''^ (\S+) \s+ (\d+)/(\S+) \s*
+                     ([^#\s] [^#]* [^#\s] | [^#\s])? \s*
+                     (?: \# \s* (\S .* \S | \S |) )? \s* $''',
+                 string, re.VERBOSE)
+    if not m:
+      raise 'Bad service line %r' % string
+    me = service(name = m.group(1),
+                 port = int(m.group(2)),
+                 proto = m.group(3),
+                 aliases = m.group(4) and m.group(4).split() or [],
+                 comment = m.group(5))
+    return me
+  parse = staticmethod(parse)
+
+class servicetab (object):
+  def __init__(me):
+    me.tab = {}
+  def _insert(me, serv):
+    tab = me.tab
+    changep = False
+    if serv.key() not in tab:
+      tab[serv.key()] = serv
+      changep = True
+    else:
+      s = tab[serv.key()]
+      d = {}
+      for a in s.aliases:
+        d[a] = 1
+      #warnp = True
+      dd = {}
+      for a in serv.aliases:
+        dd[a] = 1
+        if a not in d:
+          #if warnp:
+          #  print >>stderr, 'Merging aliases for %s' % s
+          #  warnp = False
+          s.aliases += [a]
+          changep = True
+      #for a in s.aliases:
+      #  if a not in dd:
+      #    if warnp:
+      #      print >>stderr, 'Merging aliases for %s' % s
+      #      warnp = False
+    return changep
+  def scan(me, file):
+    changep = False
+    for l in open(file):
+      if re.match(r'^\s*(\#.*)?$', l):
+        continue
+      serv = service.parse(l)
+      if me._insert(serv):
+        changep = True
+    if not changep:
+      print >>stderr, 'File `%s\' redundant' % file
+    return changep
+  def write(me):
+    kk = me.tab.values()
+    kk.sort(lambda x, y: cmp(x.key(), y.key()))
+    print '## services file [generated]'
+    print
+    for s in kk:
+      print '%-20s %9s %s' % (s.name,
+                              '%d/%s' % (s.port, s.proto),
+                              ' '.join(s.aliases))
+
+if 'running_under_emacs_p' not in globals():
+  t = servicetab()
+  for f in argv[1:]:
+    t.scan(f)
+    t.write()