# 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
}