# ppt5.awk version 1 by Ben Collver
#
# Format 5-bit values as 5 hole tape. (ISO 1154 paywalled)
#
# <https://web.archive.org/web/20040408201444/
# http://homepages.cwi.nl/~dik/english/codes/punched.html>

function bin2dec(str,    dec, hex) {
   hex = bin2hex(str)
   dec = hex2dec(hex)
   return dec
}

function bin2hex(str,    chunk, n, i, hex, pad, rem) {
   str = zpad4(str)
   n = length(str)
   for (i = 1; i <= n; i += 4) {
       chunk = zpad4(substr(str, i, 4))
       hex = hex b2h[chunk]
   }
   return hex
}

function dec2bin(dec,    hex, bin) {
   hex = sprintf("%x\n", dec)
   bin = hex2bin(hex)
   return bin
}

function hex2bin(hex,    n, i, bin) {
   n = length(hex)
   for (i = 1; i <= n; i++) {
       bin = bin h2b[substr(hex, i, 1)]
   }
   sub(/^0+/, "", bin)
   if (length(bin) == 0) {
       bin = "0"
   }
   return bin
}

function hex2dec(val,    out, i, n) {
   if (val ~ /^0x/) {
       val = substr(val, 3)
   }
   n = length(val)
   for (i = 1; i <= n; i++) {
       out = (out * 16) + h2d[substr(val, i, 1)]
   }
   #return sprintf("%.0f", out)
   return out
}

function init() {
   split("0 1 2 3 4 5 6 7 8 9 A B C D E F", hex, " ")
   split("0000 0001 0010 0011 0100 0101 0110 0111 " \
         "1000 1001 1010 1011 1100 1101 1110 1111", bin, " ")

   for (i = 0; i < 256; i++) {
       c = sprintf("%c", i)
       ord[c] = i
   }

   # bin/dec/hex conversion tables
   for (i in hex) {
       hu = hex[i]
       hl = tolower(hu)
       h2b[hl] = h2b[hu] = bin[i]
       h2d[hl] = h2d[hu] = i - 1
       b2h[bin[i]] = hu
   }
}

function main() {
   decode = 0
   ignore = 0
   if (ARGV[1] == "decode") {
       delete ARGV[1]
       decode = 1
   }
}

function zpad4(str,    pad, rem) {
   rem = length(str) % 4
   if (rem > 0) {
       pad = substr("0000", 1, 4 - rem)
       str = pad str
   }
   return str
}

BEGIN {
   init()
   main()
   if (!decode) {
       RS="\377"
       print "________"
   }
}

END {
   if (!decode) {
       print "--------"
   }
}

/^________$/ && decode {
   ignore = 1
}

/^--------$/ && decode {
   ignore = 1
}

{
   if (ignore) {
       ignore = 0
       next
   }
   if (decode) {
       if (!/^|[ o][ o][ o]\.[ o][ o]|$/) {
           printf "Error: Invalid ppt5 input: %s\n", $0
           exit 1
       }
       s = substr($0, 2, 3) substr($0, 6, 2)
       gsub(/ /, "0", s)
       gsub(/o/, "1", s)
       d = bin2dec(s)
       printf "%c", d
   } else {
       len = length($0)
       for (i = 1; i <= len; i++) {
           c = substr($0, i, 1)
           d = ord[c]
           if (d > 32) {
               printf "Error: Character won't fit in 5 bits: %c(%d)\n", c, d
               exit 1
           }
           b = dec2bin(d)
           s = sprintf("%5s", b)
           gsub(/0/, " ", s)
           gsub(/1/, "o", s)
           printf "|%s.%s|\n", substr(s, 1, 3), substr(s, 4, 2)
       }
   }
}