Version 13 of Comp3 data conversion

Updated 2009-03-26 13:23:44 by jscottb

Function to convert comp3 packed decimal data (aka BCD) (see [L1 ]) to a string.

Note: This function assumes it's signed data.

 proc comp3tostring {packed_dec_data data_len} {
    set val 0
    set ret_sign {}

    for {set byte_ndx 0} {$byte_ndx < $data_len} {incr byte_ndx} {
       scan [string index $packed_dec_data $byte_ndx] %c byte
       set byte [format "%02.2x" $byte]
       if {$byte_ndx == [expr {$data_len - 1}]} {
          append val [format "%x" [string index $byte 0]]
          if {[string index $byte 1] == {d}} {
             set ret_sign {-}
          }
       } else {
          append val "[format "%x%x" [string index $byte 0] [string index $byte 1]]"
       }
    }

    return "$ret_sign$val"
 }

RS 2009-03-24: Here's a simpler alternative:

 proc comp3int x {
    binary scan $x H* hex
    scan $hex %d int; # make sure it's int size, else use '%ld' for longs.
    switch -- [string index $hex end] {
       c {}
       d {set int -$int}
       default {return -code error "bad comp3 number: $x"}
    }

    return $int
 }

Richard, after looking at the code again, I see you include the sign digit as part of the numbers value. This function would work fine on unsigned data but not signed. Made changes to make that one work.


RS Of course it worked before I posted it... (tested with the examples on the page linked above). I use scan for two purposes: strip off leading zeroes except maybe a single one, and: stop parsing at the first non-decimal character (the last char can according to spec only be "c" or "d"). Demo:

 % scan 01234d %d
 1234

JSB Okay... I see my problem now. My function did not care about return data size. Your code worked for me on most data, but not all. After a quick look at the data in question, I see that it was failing on very large (a long) numbers (bad data, bad data!;). Changing the scan to a '%ld' made it work fine for me. Thanks!