diff --git a/bin/htmlent b/bin/htmlent
new file mode 100755
index 00000000..e5d04d9c
--- /dev/null
+++ b/bin/htmlent
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+
+# Encode/decode HTML entities in stdin or given file(s).
+
+import getopt
+import sys
+import os
+import fileinput
+import html
+from html.entities import entitydefs
+
+ENTITIES = {value: key for key, value in entitydefs.items()}
+
+def encode(text):
+ t = ""
+ for c in text:
+ if c in ENTITIES:
+ t += "&" + ENTITIES[c] + ";"
+ else:
+ t += c
+ return t
+
+def decode(text):
+ return html.unescape(text)
+
+def usage():
+ # TODO Improve this
+ print("Usage: {} [-edh] file1[ file2[ ...]]".format(os.path.basename(sys.argv[0])))
+
+
+if __name__ == '__main__':
+ COMMANDS = {
+ "-e": encode,
+ "-d": decode
+ }
+
+ try:
+ optlist, args = getopt.getopt(sys.argv[1:], 'edh')
+ sys.argv = [sys.argv[0]] + args
+ except getopt.GetoptError as err:
+ print(err)
+ sys.exit(1)
+
+ action = encode
+ for o, a in optlist:
+ if o in COMMANDS:
+ action = COMMANDS[o]
+ elif o == '-h':
+ usage()
+ sys.exit()
+ else:
+ assert False, "unhandled option"
+
+ input = "\n".join([line for line in fileinput.input()]).strip()
+ print(action(input))