David Megginson wrote:
> Last time I looked at swig, it was for creating bindings for native
> libraries from include files.
>
> Try
>
>   perldoc -f pack
>   perldoc -f unpack
>
> Perl has excellent support for this kind of thing, once you get your
> head around it.

BIG WARNING: The pack/unpack facilities have been pretty thoroughly
cuisinarted by the recent UTF8 support.  I got smacked hard by this a
few months back.

Attached is a little mind bender that I wrote while trying to figure
this out.  All it does is take a number (255), and try to pack that as
a single-byte number into a one character string.  It verifies that
the length is one; writes that single byte out to a file, reads that
single byte back in from the file, and then verifies that the strings
are equal.

When run under Red Hat 8.0, the strings are *not* equal.  When run on
the same machine via an "ssh -c" command, the strings *are* equal.

What happened is that perl honors the LANG attribute when doing file
I/O, and LANG is set to "en_US.UTF-8" by default for login shells in
Red Hat.  So it writes out the (UCS-2) "character" 255 as a two byte
(!) UTF8 string.

This is sane behavior for perl in text contexts (UTF8 files turn into
character arrays magically when read, and re-stream themselves
magically when written), but it completely breaks the pack function,
which is based on the idea of packing numbers into strings and
interpreting those strings as arrays of bytes, not characters.

This is trivially fixable by clearing $ENV{LANG} in scripts where you
want to call pack/unpack, but it is very non-obvious if you aren't
prepared for it.

Andy

--
Andrew J. Ross                NextBus Information Systems
Senior Software Engineer      Emeryville, CA
[EMAIL PROTECTED]              http://www.nextbus.com
"Men go crazy in conflagrations.  They only get better one by one."
 - Sting (misquoted)
#!/usr/bin/perl -w
use strict;
use bytes;

my $s0 = pack "C", 255;
print "Length: ", length($s0), "\n";
print "Bytes: ", join(", ", unpack("C*", $s0)), "\n";

open FOO, ">foo.out" or die;
print FOO $s0;
close FOO;

my $s1;
open FOO, "foo.out" or die;
read(FOO, $s1, 1) == 1 or die;
close FOO;

print "Length: ", length($s1), "\n";
print "Bytes: ", join(", ", unpack("C*", $s1)), "\n";

if($s0 eq $s1) { print "Strings are equal\n"; }
else           { print "Strings are NOT equal\n"; }

Reply via email to