lee@sq.sq.com (Liam R. E. Quin) (12/06/89)
Did you ever look at an octal (or hex, or...) dump of something and say to yourself, `well, those three bytes might represent the size of the...'? I wrote the following little calculator... you can say 371 10 1 0 and it comes back with 0... 1... 264... 67833... dec 67833 oct 0204371 hex 0x108f9 so you can see that if these four octal bytes were stored in memory, they'd represent the decimal number 67833 (assuming intel byte ordering). You can type any reasonable number of clumps of digits to make an n-byte word. You can change the byte ordering and the bases used: sane, mc68k, mc68000 -- least significant "clump" is on the left intel, vax -- least significant "clump" is on the right so it does a b c d and d c b a, but not b a d c. You could easily change it. Note that byte ordering only affects the order in which clumps of digits are processed, not the digits within the clumps, so intel and sane 10 23 45 45 23 10 are equivalent. The bases can be changed with ibase (for the base you're using to type the byte values) and obase (to tell it what constitutes a byte -- default is 256, of course, but if you use 1 you get a primitive adding machine :-). You can say "obase hex" or "ibase = 10" -- either syntax is known. Of course, saying "ibase = 10" is always a no-op, so the following are also known: hex (or hexadecimal) = 16, oct (octal) = 8, byte = 256, dec(imal) = 10 Oh, and "info" gives current status information. [ anyway, time for the awk-lovers to hit back against the evil perl :-) :-)] Lee : To unbundle, sh this file a - bcalc echo x - bcalc 1>&2 sed 's/^X//' >bcalc <<'@@@End of bcalc' X#! /usr/local/bin/nawk -f X X# Liam Quin's very simple byte calculator. X# On system V, use nawk -f this-file-name, perhaps in a little shell-script. X# Needs the new awk (nawk on SysV, or MKS awk, or from the AT&T toolchest) X XBEGIN { X convtype = "octal"; obase = 256; ibase = 8; clumpbase = 256 X intel = 1 # Well, you can change it if you want X for (i = 0; i < 10; i++) { X values[i ""] = i X } X # set up octal/hex/arbitrary base digits X values["a"] = 10 values["A"] = 10 values["b"] = 11 values["B"] = 11 X values["c"] = 12 values["C"] = 12 values["d"] = 13 values["D"] = 13 X values["e"] = 14 values["E"] = 14 values["f"] = 15 values["F"] = 15 X X radix["octal"] = 8 radix["oct"] = 8 X radix["decimal"] = 10 radix["dec"] = 10 X radix["hexadecimal"] = 16 radix["hex"] = 16 X radix["sex"] = 60 radix["byte"] = 256 # output only... X radix["liam"] = 42 X} X X/^[ ]*$/ { next } X X# clumpbase lets you specify the base with which clumps are combined X# Allow built-in keywords like "obase hex" for sanity... X($1 == "clumpbase" || $1 == "obase" || $1 == "cbase") { X if (NF == 3 && ($2 == "=" || $2 == "==")) clumpbase = $3 X else clumpbase = $2 X if (clumpbase in radix) { X clumpbase = radix[clumpbase] X } else if (clumpbase ~ /^[0-9a-fA-F]+$/) { X tmp = conv(clumpbase) X clumpbase = tmp # might not get here if conv() does a "next" X } X printf "obase set to %d (0%o, 0x%x)\n", clumpbase, clumpbase, clumpbase X next X} X X# conv lets you specify how the lumps within the clumps are interpreted. X# max is currently 16 X($1 == "ibase") { X if (NF == 3 && ($2 == "=" || $2 == "==")) convtype = $3 X else convtype = $2 X if (convtype in radix) { X ibase = radix[convtype] X } else if (convtype ~ /^[0-9a-fA-F]+$/) { X tmp = conv(convtype) X if (tmp > 16) { X printf "Largest supported base is 16, sorry (runs out of digits)\n" X printf "%d is too big.\n", tmp X next X } X ibase = tmp # might not get here if conv() does a "next" X } else { X printf "Invalid conv type \"%s\"\n", convtype X next X } X printf "ibase set to %s (base %d [decimal])\n", convtype, ibase X next X} X X(NF == 1) { X if ($1 ~ /^[qQ]([uU][iI][tT])?/) { exit 0 } X else if ($1 == "help") { X print "You're on your own, boy!" X printf "\t\t\t\t\t\t(info is better)\n" X next X } else if ($1 == "info") { Xprint "bcalc -- very simple byte calculator" Xprint " clumps of digits are each read in base \"ibase\", and are combined" X if (intel) printf " (right to left) " X else printf " (left to right) " Xprint " as if they were each digits in base \"obase\"." Xprintf " Change the bases (currently obase=%d, ibase=%d) with the\n", X obase, ibase Xprint " obase and ibase commands." Xprint " Use \"intel\" or \"sane\" to control byte ordering.\n" X next X } else if ($1 == "intel" || $1 ~ /^[vV][aA][xX]$/) { X intel = 1 X print "Using looney clump ordering, lsb on left" X next X } else if ($1 == "sane" || $1 ~ /^[mM][cC]68(0|[kK])+/) { X intel = 0 X print "Using sane clump ordering, lsb on right" X next X } X} X X(NF > 0) { X val = 0 X printf "\t" X if (intel) { X for (i = NF; i >= 1; i--) { X val = val * clumpbase X val = val + conv($(i)) X printf "%d... ", val X } X } else { X for (i = 1; i <= NF; i++) { X val = val * clumpbase X val = val + conv($(i)) X printf "%d... ", val X } X } X printf "\n" X printf "dec %d oct 0%o hex 0x%x\n", val, val, val X next X} X X{ X print "Error: " X print X next X} X Xfunction conv(n, r, s, d, l, dig) X{ X if (ibase == 10) { # special case X if (n ~ /^[0-9]+$/) return n X else printf "Decimal %s contains strange numbers...\n", n X next X } else { X if (convtype == "octal" && !(n ~ /^[0-7]+$/)) { X printf "Octal %s contains strange numbers...\n", n X next X } X r = 0 X s = "0" n X l = length(s) X for (d = 1; d <= l; d++) { X dig = substr(s, d, 1) X if (dig == "") dig = "0" # mks awk bug (mks sucks) X # printf "\ts is \"%s\", l is %d, d is %d, dig is \"%s\"\n", X # s, l, d, dig X if (dig in values) { X if (values[dig] >= ibase) { X printf "base %d [dec] number has illegal digit %s\n", X ibase, dig X next X } X r = r * ibase + values[dig] X } else { X printf "\"%s\" contains strange digit \"%s\" (not hex)\n", X n, dig X next X } X } X return r X } X} @@@End of bcalc -- Liam R. Quin, Unixsys (UK) Ltd [note: not an employee of "sq" - a visitor!] lee@sq.com (Whilst visiting Canada from England, until Christmas) ...striving to promote the interproduction of epimorphistic conformability