aboutsummaryrefslogtreecommitdiff
path: root/bin/mi5.awk
diff options
context:
space:
mode:
Diffstat (limited to 'bin/mi5.awk')
-rw-r--r--bin/mi5.awk133
1 files changed, 133 insertions, 0 deletions
diff --git a/bin/mi5.awk b/bin/mi5.awk
new file mode 100644
index 00000000..7acb6f3b
--- /dev/null
+++ b/bin/mi5.awk
@@ -0,0 +1,133 @@
+# Crude m4 preprocessor
+BEGIN {
+ self = "mi5"
+
+ # You can change any of these, but while changing these is still relatively
+ # sane...
+ open = "<%"
+ shut = "%>"
+
+ # ... changing these probably isn't, and should compel you to rethink your
+ # code, or quite possibly your entire life thus far.
+ quote = "`"
+ unquote = "'"
+ dnl = "dnl"
+
+ # We do not start in a block
+ bmac = 0
+}
+
+# Fatal error function
+function fatal(str) {
+ stderr = "cat >&2"
+ printf "%s: %s\n", self, str | stderr
+ close(stderr)
+ exit(1)
+}
+
+# Print an m4 opener as the first byte
+NR == 1 { printf "%s", quote }
+
+# Blocks
+NF == 1 && $1 == open && !bmac++ {
+ printf "%s", unquote
+ next
+}
+NF == 1 && $1 == shut && bmac-- {
+ printf "%s", quote
+ next
+}
+
+# If in a block, print each line with any content on it after stripping leading
+# and trailing whitespace
+bmac && NF {
+ gsub(/(^ +| +$)/, "")
+ print $0 dnl
+}
+
+# If not in a block, look for inlines to process
+!bmac {
+
+ # We'll parse one variable into another.
+ src = $0
+ dst = ""
+
+ # Start off neither quoting nor macroing.
+ iquo = imac = 0
+
+ # Crude and slow, clansman. Your parser was no better than that of a clumsy
+ # child.
+ for (i = 1; i <= length(src); ) {
+
+ # Inline macro expansion: commented
+ # Look for end of comment and tip flag accordingly
+ if (iquo)
+ iquo = (substr(src, i, length(unquote)) != unquote)
+
+ # Inline macro expansion
+ else if (imac) {
+
+ # Close the current inline macro expansion if a close tag is found
+ # (in m4 terms: open a new quote), looking ahead past any spaces
+ # from this point first
+ for (j = i; substr(src, j, 1) ~ /[ \t]/; j++)
+ continue
+ if (substr(src, j, length(shut)) == shut) {
+ dst = dst quote
+ i = j + length(shut)
+ imac = 0
+ continue
+ }
+
+ # Look for start of comment and tip flag accordingly
+ iquo = (substr(src, i, length(quote)) == quote)
+ }
+
+ # Plain text mode
+ else {
+
+ # Open a new inline macro expansion if an open tag is found (in m4
+ # terms: close the quote), and then look ahead past any spaces from
+ # that point afterward
+ if (substr(src, i, length(open)) == open) {
+ dst = dst unquote
+ imac = 1
+ for (i += length(open); substr(src, i, 1) ~ /[ \t]/; i++)
+ continue
+ continue
+ }
+
+ # Escape quote terminators
+ if (substr(src, i, length(unquote)) == unquote) {
+
+ # Dear Mr. President. There are too many variables nowadays.
+ # Please eliminate three. I am NOT a crackpot.
+ dst = dst unquote unquote quote
+
+ i += length(unquote)
+ continue
+ }
+ }
+
+ # If we got down here, we can just add the next character and move on
+ dst = dst substr(src, i++, 1)
+ }
+
+ # If we're still in a macro expansion or quote by this point, something's
+ # wrong; say so and stop, rather than print anything silly.
+ if (iquo)
+ fatal("Unterminated inline quote")
+ else if (imac)
+ fatal("Unterminated inline macro")
+ else
+ print dst
+}
+
+# Print an m4 closer and newline deleter as the last bytes if we've correctly
+# stopped all our blocks
+END {
+ if (bmac)
+ fatal("Unterminated block macro")
+ else
+ print unquote dnl
+}