On Aug 7, 3:55 pm, James Edward Gray II <ja... / grayproductions.net>
wrote:
> On Aug 7, 2007, at 4:23 PM, Daniel Berger wrote:
> > On Aug 7, 2:10 pm, James Edward Gray II <ja... / grayproductions.net>
> > wrote:
> >> On Aug 7, 2007, at 3:04 PM, Daniel Berger wrote:
>
> >>> I think you're better off using this snippet that Greg Hurrell
> >>> showed
> >>> you earlier this year instead of shelling out at all. I've
> >>> modified it
> >>> to use the correct value of TIOCGWINSZ for Solaris:
>
> >>> TIOCGWINSZ = 21608
> >>> buf = [0, 0, 0, 0].pack('SSSS')
> >>> if $stdin.ioctl(TIOCGWINSZ, buf) >= 0
> >>>   rows, cols, xpixels, ypixels = buf.unpack("SSSS")
> >>>   p rows, cols, xpixels, ypixels
> >>> else
> >>>   puts "Unable to get window size"
> >>> end
>
> >> Can you explain why you feel the above is "better?"
>
> > Because the output is predictable and therefore more reliable. It also
> > doesn't require forking off a new process.
>
> > I've no idea if the output from 'stty -a' is the same from Solaris
> > 2.5.1 through Solaris 10. Also, have you verified that shelling out to
> > stty returns the output you expect on other platforms such as HP-UX or
> > AIX?
>
> > Mind you, this approach requires figuring out the appropriate value
> > for TIOCGWINSZ for each platform (which probably doesn't change
> > between releases), but that's easier than parsing stdout for each
> > platform IMHO.
>
> It's this magic number work that scares me.  In fact, the entire
> chunk of code above is pretty opaque to me.
>
> On the flip size, I understand exactly what the stty code does and
> how it works.  If it someone complains that it's broken on HP-UX,
> AIX, or their POSIX-compliant toaster, we will add another branch in
> the if chain.
>
> I don't see that as any more maintenance than finding the magic
> number and I know how to ask users to help me do the former.
>
> Ronald parsed the output for Solaris with a single trivial Regexp, so
> that didn't feel like a significant hurdle to me.
>
> In short, I'm comfortable with the stty approach.  So far I haven't
> seen it blow up in anyway that I feel we would escape using ioctl().

Fair enough.

I thought I'd take a moment to explain that code a bit better. I
figure it might make it seem less opaque to you, and perhaps others
who stumble onto this thread later on will find it useful.

First, the code supplied above requires visually inspecting the
termios.h file on your system (yep, sorry, no way around that). It's
probably under /usr/include or /usr/include/sys (or you can probably
find its declaration online). That's where I got the value for
TIOCGWINSZ - it's a #define'd value.

Moving on, I realized that the row and column data (along with the
xpixel and ypixel data) is stored in structure called 'winsize'. It's
declared like so:

/* Windowing structure to support JWINSIZE/TIOCSWINSZ/TIOCGWINSZ */
struct winsize {
   unsigned short ws_row;     /* rows, in characters */
   unsigned short ws_col;     /* columns, in character */
   unsigned short ws_xpixel;  /* horizontal size, pixels */
   unsigned short ws_ypixel;  /* vertical size, pixels */
};

That's why we defined the 'buf' like this:

buf = [0, 0, 0, 0].pack('SSSS')

That says give me a data buffer large enough to hold four unsigned
short integers. We could just as well have done "buf = 0.chr * 8", but
the above notation is more explicit, to C programmers anyway, about
what that 'buf' really is, i.e. a data buffer large enough to hold a
struct with 4 members.

We then pass 'TIOCGWINSZ' and 'buf' as arguments to $stdin.ioctl. The
buf is passed by reference, meaning it will be filled with the
appropriate values after the call.

After ioctl has been called we have to unravel the buf the same way we
created it. That's how we end up with this bit:

rows, cols, xpixels, ypixels = buf.unpack('SSSS')

Hope that helps.

Dan