in reply to Re^2: Don't understand why can't get 'size' assoc w/STDOUT
in thread Don't understand why can't get 'size' assoc w/STDOUT

perl-diddler wrote something that — after copyediting and HTML formatting — ran something like:
Your program (and your complete ‘overkill’ solution) led me to finding the solution — as I took your overkill solution and stripped out the C and converted it to Perl, and that finally highlighted what was wrong with my original program. The problem is nothing to do with a “problem with STDOUT” — it’s the **result** word. Changing the line:
my $winsize=0;
to
my $winsize= ' ' x 8;
Solves the problem. It works. (' ' x 8 " =~= your "\0" x 8)

At this point, the problem is clear: the Perl ioctl doesn’t allocate space for the return value — it expects the space to already be there. The ‘Bad address’ error message that comes back is a reference to my having given the C version of the ioctl syscall a bad address for the result buffer.

Once I give it the needed space (for 4 ‘shorts’) — it’s happy!

ARGGGG!!!! I’ve been programming in Perl for too long and forgotten my “C” basics...

Well, yes: it’s always good to do systems programming is C now and then: it reminds you how it’s done. :)

The Perl ioctl function has documentation in the perlfunc manpage that explains what happened to you, albeit perhaps not quite as clearly as one might wish:

SCALAR will be read and/or written depending on the FUNCTION; a C pointer to the string value of SCALAR will be passed as the third argument of the actual ioctl call. (If SCALAR has no string value but does have a numeric value, that value will be passed rather than a pointer to the string value. To guarantee this to be true, add a 0 to the scalar before using it.)
As you have (re?)discovered, there is of course no possible way for Perl to know how large a buffer to prepare for whatever ioctl you happen to be calling to write however much data it wants there. Different ioctls need different things, and Perl cannot know one from another. It just makes the syscall and expects you to Do The Right Thing. After that, well — the kernel is certainly not about to allocate memory for you! :)

By assigning your variable a value of integer 0, you managed to trick Perl into supplying a mere number to an ioctl that actually needed not a little numeric value but rather a place to write return values into.

And here is an example from Programming Perl:

require "sys/ioctl.ph"; $size = pack("L", 0); ioctl(FH, FIONREAD(), $size) || die "Couldn't call ioctl: $!\n"; $size = unpack("L", $size);
Which also shows the need to pre-allocate enough memory for ioctl to write into. I suppose I could make this point clearer. I tend to find that nowadays most people look at me like I’m trying to address them in Homeric Greek if I ever bring up ioctls — or C coding, for that matter.

My so-called “overkill” solution was there to show you the C code needed to get the right structure size on your system so you could make something big enough, and also of course how to get the right value for the ioctl argument that works on your system — they do vary, as my sample runs demonstrated — instead of praying that you have a proper sys/ioctl.ph installed. My first version was just the C one, but then I figured I might as well show you the magical Inline::C version, which is kinda nifty.