#! /usr/bin/awk -f # # ledger balance calculator # # usage: # [colorize=false] [scale=N] //ledger/lib/balance LEDGER_FILE... # [colorize=false] [scale=N] //ledger/lib/balance < LEDGER_FILE # # description: # The ledger balance calculator computes the balance of each account it # encounters in the provided ledger files. # # example: # //ledger/lib/balance < //cholerab/ledger-spec.markdown # # see also: # //cholerab/ledger-spec.markdown (ledger file format) # BEGIN { colorize = ENVIRON["colorize"] == "" || ENVIRON["colorize"] == "true" # TODO use bc for arbitrary precision arithmetic scale = ENVIRON["scale"] } /^[[:space:]]*[0-9]+-[0-9][0-9]-[0-9][0-9]/{ tx($2, $3, $4, $5) } END { display_accounts() } function tx (dst, src, amt, u) { withdraw(src, amt, u) deposit(dst, amt, u) } function deposit (name, amt, u) { accounts[name][u] += amt } function withdraw (name, amt, u) { accounts[name][u] -= amt } function display_accounts() { max_name_len = 0 for (name in accounts) { if (length(name) > max_name_len) { max_name_len = length(name) } } max_balance_len = 0 for (name in accounts) { for (u in accounts[name]) { n = length(int(accounts[name][u])) if (n > max_balance_len) { max_balance_len = n } } } if (scale > 0) { max_balance_len += length(".") + scale } for (name in accounts) { for (u in accounts[name]) { balance = accounts[name][u] if (balance == 0) { continue } fmt = "NAME BALANCE UNIT\n" if (colorize) { sub("BALANCE", "[" (balance < 0 ? 31 : 32) "m&", fmt) } sub("NAME", "%-" max_name_len "s", fmt) sub("BALANCE", "%" max_balance_len "." scale "f", fmt) sub("UNIT", "%s", fmt) printf fmt, name, balance, u } } }