From: Tom Christiansen <tchrist@convex.COM>
Subject: Re: more unpack questions
Originator: tchrist@pixel.convex.com
Reply-To: tchrist@convex.COM (Tom Christiansen)
Organization: CONVEX Realtime Development, Colorado Springs, CO
Date: Thu, 16 Apr 1992 16:20:29 GMT
X-Disclaimer: This message was written by a user at CONVEX Computer
              Corp. The opinions expressed are those of the user and
              not necessarily those of CONVEX.

From the keyboard of chare@unilabs.uucp (Chris Hare):
:I have an array of 40 chars, which contains 13 block addresses. (Yes, this
:is from an inode).  Each three chars form an address.

One of my favorite kinds of questions.  First some confusion:

    3 * 13 == 39, != 40.
    sizeof(int) == 4, != 3.

But I'll assume you know what is happening on your system.  

:
:If I used the following to unpack the data, I get zeros.  Why?
:
:   ( $di_mode, $di_nlink, $di_uid, $di_gid, $di_size, $di_addr,
:	 $di_atime, $di_mtime, $di_ctime ) = unpack( $DiskInode, $ibuf );

I'll assume that you've loaded an accurate structure template into the 
$DiskInode variable.  What this really is will vary widely between 
systems.   Your only hope of a semi-portable program is to use c2ph
generate struct definitions.  If you don't care about this, you'd still
better be careful to lay out your template right, and might want to 
use c2ph just for that.

On my system, the structure in question looks like this:

    {
	package icommon;

	# package private data; use &forms for outside:

	    $typedef = 'S s3 i23 S C2 i6';
	    $sizeof = 128;
	    @indices = (0..4,6..12,24,27..32);

	# these are public entry points:

	sub ic_mode                  {    0; }
	sub ic_nlink                 {    1; }
	sub ic_uid                   {    2; }
	sub ic_gid                   {    3; }
	sub ic_size                  {    4; }
	sub ic_atime                 {    6; }
	sub ic_atspare               {    7; }
	sub ic_mtime                 {    8; }
	sub ic_mtspare               {    9; }
	sub ic_ctime                 {   10; }
	sub ic_ctspare               {   11; }
	sub ic_db                    {   12; }
	sub ic_ib                    {   24; }
	sub ic_dmonperm              {   27; }
	sub ic_dmonflags             {   28; }
	sub ic_sysflags              {   29; }
	sub ic_blocks                {   30; }
	sub ic_gen                   {   31; }
	sub ic_spare                 {   32; }
    }

So you could unpack it this way:

    @fields = unpack(&icommon'typedef, $ibuf);

I believe you want to get the ic_db and ic_ib fields, which are
respectively i12 and i3 formats.  (There's more information in 
the c2ph translations.)  On my system, at least &int'sizeof is 
4, not 3.  You can get at them this way

    $fields[&icommon'ic_db + $N] 

where $N is a number between 0 and 11 on my system.  A similar trick
could be performed for the indirect blocks.


:   ( $a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9, $a10, $a11, 
:	 $a12 ) = unpack( "c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3 c3", $di_addr );

Two problems here.  First of all, a 'c3' format does not pull out
3 characters and call them an integer.  It makes three one-char fields.
You may want a3 instead here, but that is still going to give you something
that's in packed integer format.  One way to do this might be:

    @addrs = unpack("a3" x 13, $di_addr;
    for (@addrs) { $_ = unpack('i', $_); }

But I'm still dubious about your 3-byte integers.

--tom
Newsgroups: comp.lang.perl