Forum: Ruby Question about String.unpack

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
C5eecd44fa818c7985d4f31bc2c42ac9?d=identicon&s=25 Eric Jacoboni (Guest)
on 2006-02-21 15:29
(Received via mailing list)
Hi,

Say i've a C struct like that:

typedef struct {
  char name[30];
  double size;
  int age;
  char stuff;
} enreg_t;

This record is written in a file that i want to re-read with a Ruby
script (just a toy example... to understand).

I've not found a "clean" way to unpack such a record...

My C compiler gives me a total sizeof of 48, so i use a
  fd.sysread(48).unpack(A32dIC) to re-read. But that seems rather
  'tricky' (i suppose we don't have always such a
  information). Furthermore, the first element is completed with
  garbage if the name field have less than 30 "useful" chars ("Doe",
  for example).

I'm sure i'm missing something but i've not managed to find the right
way to do that.

Any clue?
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-02-21 20:14
(Received via mailing list)
On Feb 21, 2006, at 9:28 AM, Eric Jacoboni wrote:

>
>   for example).
>
> I'm sure i'm missing something but i've not managed to find the right
> way to do that.
>
> Any clue?
> --
> Eric Jacoboni, ne il y a 1443970729 secondes
>

there isn't really a "clean" way to do this, since you are doing
something inherently un-clean.
However, to fix the string issue, a possible solution is:

str.gsub!(/\000.*/, '')

assuming of course that name is a c-string.
E96756693ee0fc927a805ba0d509df72?d=identicon&s=25 Jacob Repp (Guest)
on 2006-02-21 20:20
(Received via mailing list)
I'm curious about binary protocol parsing in ruby and have scratched
around for some kind of BinaryReader-ish interface for strings. Seems
like you could solve this if you know that your struct is in a string
you could say:

str = fd.sysread(n)
name = str.read_str(30)
size = str.read_double
age = str.read_int
stuff = str.read_c

I was going to write a native extension to do this after I finish my
current Ruby/AIO extension project. Unless there is something that
does this already (maybe in a cleaner/more ruby-ish way?)
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-02-21 20:51
(Received via mailing list)
On Feb 21, 2006, at 2:19 PM, Jacob Repp wrote:

>
> I was going to write a native extension to do this after I finish my
> current Ruby/AIO extension project. Unless there is something that
> does this already (maybe in a cleaner/more ruby-ish way?)

This is pretty much exactly what unpack does anyway., except its one
method that uses a format string. If you wanted a more stream
oriented wrapper around this, you certainly could write one fairly
easily.

ri String#unpack
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2006-02-22 07:29
(Received via mailing list)
On Feb 21, 2006, at 6:28 AM, Eric Jacoboni wrote:

> script (just a toy example... to understand).
>
> I've not found a "clean" way to unpack such a record...
>
> My C compiler gives me a total sizeof of 48, so i use a
>   fd.sysread(48).unpack(A32dIC) to re-read. But that seems rather

Your struct says char name[30] not 32...

>   'tricky' (i suppose we don't have always such a
>   information). Furthermore, the first element is completed with
>   garbage if the name field have less than 30 "useful" chars ("Doe",
>   for example).

Did you initialize the C struct correctly?  You should zero out all
of name.

> I'm sure i'm missing something but i've not managed to find the right
> way to do that.

--
Eric Hodel - drbrain@segment7.net - http://segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
956f185be9eac1760a2a54e287c4c844?d=identicon&s=25 ts (Guest)
on 2006-02-22 11:11
(Received via mailing list)
>>>>> "E" == Eric Hodel <drbrain@segment7.net> writes:

>> My C compiler gives me a total sizeof of 48, so i use a
>> fd.sysread(48).unpack(A32dIC) to re-read. But that seems rather

E> Your struct says char name[30] not 32...

 Yes, but there is alignement

 He just want Z32 rather than A32

biocluster1% cat a.c
#include <stdio.h>
#include <string.h>

typedef struct {
    char name[30];
    double size;
    int age;
    char stuff;
} enreg_t;

main()
{
    FILE *fd;
    enreg_t enreg;
    strcpy(enreg.name, "abc");
    enreg.size = 12.0;
    enreg.age = 12;
    enreg.stuff = 'a';
    fd = fopen("aa", "w");
    fwrite(&enreg, sizeof(enreg), 1, fd);
    fclose(fd);
}
biocluster1%

biocluster1% ruby -e 'p a = IO::read("aa"); p a.unpack("Z32dIC")'
"abc\000\030\373\377\277U\203\004\010tp\001@\360z\001@8\373\377\277K\205\004\010\200\270\024@\000\000\000\000\000\000(@\f\000\000\000ae\001@"
["abc", 12.0, 12, 97]
biocluster1%


Guy Decoux
2c51fec8183a5d21c4e11b430beabb47?d=identicon&s=25 Patrick Hurley (Guest)
on 2006-02-22 14:33
(Received via mailing list)
On 2/22/06, ts <decoux@moulon.inra.fr> wrote:
> >>>>> "E" == Eric Hodel <drbrain@segment7.net> writes:
>
> >> My C compiler gives me a total sizeof of 48, so i use a
> >> fd.sysread(48).unpack(A32dIC) to re-read. But that seems rather
>
> E> Your struct says char name[30] not 32...
>
>  Yes, but there is alignement
>
>  He just want Z32 rather than A32

I would suggest that Z30xx would be a better choice.

pth
02f36d0f9d518cc75ac6ee8a6644f982?d=identicon&s=25 David Holroyd (Guest)
on 2006-02-22 14:45
(Received via mailing list)
On Wed, Feb 22, 2006 at 04:19:07AM +0900, Jacob Repp wrote:
>
> I was going to write a native extension to do this after I finish my
> current Ruby/AIO extension project. Unless there is something that
> does this already (maybe in a cleaner/more ruby-ish way?)

Yes, I've needed one of these too (read + write).  My application was
handling a binary UDP protocol.  String#unpack doesn't support some of
the bizarro data formating that this protocol seems to have, so I cooked
up ReadBuffer/WriteBuffer[1] classes with a few methods a bit like those
above.

...just my 2-pence-use-case.


dave

[1] http://svn.badgers-in-foil.co.uk/alchemic/trunk/na...
C5eecd44fa818c7985d4f31bc2c42ac9?d=identicon&s=25 Eric Jacoboni (Guest)
on 2006-02-22 16:25
(Received via mailing list)
ts <decoux@moulon.inra.fr> writes:

> E> Your struct says char name[30] not 32...
>
>  Yes, but there is alignement
>
>  He just want Z32 rather than A32

Thanks...

BTW: Eric, your message was not propagated to my Usenet Server...
This topic is locked and can not be replied to.