Need Solaris Help

I’m told the following bit of code doesn’t work on Solaris:

   # A Unix savvy method to fetch the console columns, and rows.
   def terminal_size
    `stty size`.split.map { |x| x.to_i }.reverse
   end

HighLine makes use of this method as does Capistrano by extension, so
we need find a portable solution.

Can anyone provide an equivalent technique that works on Solaris?

Thanks.

James Edward G. II

On 8/7/07, James Edward G. II [email protected] wrote:

I’m told the following bit of code doesn’t work on Solaris:

   # A Unix savvy method to fetch the console columns, and rows.
   def terminal_size
    `stty size`.split.map { |x| x.to_i }.reverse
   end

HighLine makes use of this method as does Capistrano by extension, so
we need find a portable solution.

Ruport vendors this chunk of code, so sorry for the ‘me too’, but me
too!

On 8/7/07, Gregory B. [email protected] wrote:

we need find a portable solution.

Ruport vendors this chunk of code, so sorry for the ‘me too’, but me too!

This is not pretty but it works on my Solaris 10 x64 box. But you may
have
been looking
for something more elegant.

if stty =~ /.\brows = (\d+).\bcolumns = (\d+)/
rows = $1
columns = $2
end

Ron

Douglas F Shearer wrote:

-bash-3.00# stty size
unknown mode: size
-bash-3.00# stty
speed 38400 baud; -parity
rows = 24; columns = 80; ypixels = 0; xpixels = 0;
eol = -^?; eol2 = -^?; swtch = ; flush = -^?; lnext = -^?;
brkint -inpck -istrip icrnl imaxbel onlcr tab3
echo echoe echok echoctl echoke iexten

On FreeBSD:

[alex@panama ~/noodling/rubinius]$ stty
speed 38400 baud;
lflags: echoe echoke echoctl pendin
oflags: -oxtabs
cflags: cs8 -parenb

No rows or columns. How about stty -a?

[alex@panama ~/noodling/rubinius]$ stty -a
speed 38400 baud; 62 rows; 157 columns;
lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl
-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel -ignbrk
brkint -inpck -ignpar -parmrk
oflags: opost onlcr -ocrnl -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts
-dsrflow
-dtrflow -mdmbuf
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = ;
eol2 = ; erase = ^?; erase2 = ^H; intr = ^C; kill = ^U;
lnext = ^V; min = 1; quit = ^; reprint = ^R; start = ^Q;
status = ^T; stop = ^S; susp = ^Z; time = 0; werase = ^W;

On 7 Aug 2007, at 19:20, James Edward G. II wrote:

I’m told the following bit of code doesn’t work on Solaris:
stty size.split.map { |x| x.to_i }.reverse

James Edward G. II

If it helps, the output from stty looks like the following:

-bash-3.00# stty size
unknown mode: size
-bash-3.00# stty
speed 38400 baud; -parity
rows = 24; columns = 80; ypixels = 0; xpixels = 0;
eol = -^?; eol2 = -^?; swtch = ; flush = -^?; lnext = -^?;
brkint -inpck -istrip icrnl imaxbel onlcr tab3
echo echoe echok echoctl echoke iexten

Had a quick look at the man pages, there doesn’t seem to be an alias
for size.

The man pages are also on the Sun site here: Oracle Help Center
docs/doc/816-5165/6mbb0m9tb?a=view

Hope this is of some help.

Douglas F Shearer

On 8/7/07, James Edward G. II [email protected] wrote:

Can anyone provide an equivalent technique that works on Solaris?

$ cat t.rb
def terminal_size
m = %r/rows\s(?:=\s)?(\d+);.*columns\s(?:=\s)?(\d+);/.match(stty -a)
[Integer(m[2]), Integer(m[1])]
end

puts terminal_size.inspect

$ uname -a
SunOS hedwig 5.9 Generic_112233-12 sun4u sparc SUNW,Sun-Blade-1500

$ ruby t.rb
[80, 36]

And on the Linux box …

$ uname -a
Linux pong 2.6.21-1.3228.fc7 #1 SMP Tue Jun 12 15:37:31 EDT 2007 i686
i686 i386 GNU/Linux

$ ruby t.rb
[80, 24]

Blessings,
TwP

On 8/7/07, Alex Y. [email protected] wrote:

[alex@panama ~/noodling/rubinius]$ stty -a
speed 38400 baud; 62 rows; 157 columns;

Leave it to BSD to do everything backwards! :wink:

TwP

Tim P. wrote:

puts terminal_size.inspect
$ uname -a
Linux pong 2.6.21-1.3228.fc7 #1 SMP Tue Jun 12 15:37:31 EDT 2007 i686
i686 i386 GNU/Linux

$ ruby t.rb
[80, 24]

How’s this:

[alex@panama ~/noodling/ruby]$ ruby t.rb
[157, 62]
[alex@panama ~/noodling/ruby]$ cat t.rb
def terminal_size
%r{([^;]rows[^;];)([^;]columns[^;];)}.match(stty -a)[1…-1].map{|i| i.gsub(/\D/, ‘’).to_i}.reverse
end

puts terminal_size.inspect

'Scuse the line break, but it works on FreeBSD, Linux and Cygwin+OCI…

ronald braswell writes:

On 8/7/07, Gregory B. [email protected] wrote:

On 8/7/07, James Edward G. II [email protected] wrote:

I’m told the following bit of code doesn’t work on Solaris:

   # A Unix savvy method to fetch the console columns, and 

rows.

   def terminal_size
    `stty size`.split.map { |x| x.to_i }.reverse
   end

HighLine makes use of this method as does Capistrano by
extension, so
we need find a portable solution.

Ruport vendors this chunk of code, so sorry for the ‘me too’, but
me too!

This is not pretty but it works on my Solaris 10 x64 box. But you
may have
been looking
for something more elegant.

if stty =~ /.\brows = (\d+).\bcolumns = (\d+)/
rows = $1
columns = $2
end

Ron

Here’s my stab at a cross-platform implementation:

def terminal_size
if /solaris/ =~ RUBY_PLATFORM
output = stty
[output.match(‘columns = (\d+)’)[1].to_i,
output.match(‘rows = (\d+)’)[1].to_i]
else
stty size.split.map { |x| x.to_i }.reverse
end
end

I did a quick test on Solaris (9 and 10), FreeBSD and Linux, and got
the same results in every case. (No guarantees on AIX, HP-UX, etc.)

Coey

James Edward G. II wrote:

-bash-3.00# stty size
not?

It does. I was aiming at something that would work everywhere.

On Aug 7, 2007, at 1:54 PM, Alex Y. wrote:

-bash-3.00# stty
speed 38400 baud; -parity
rows = 24; columns = 80; ypixels = 0; xpixels = 0;
eol = -^?; eol2 = -^?; swtch = ; flush = -^?; lnext = -^?;
brkint -inpck -istrip icrnl imaxbel onlcr tab3
echo echoe echok echoctl echoke iexten
On FreeBSD:

I assume the current code (using stty size) works on FreeBSD. Does
it not?

James Edward G. II

On Aug 7, 2007, at 2:17 PM, Coey M. wrote:

   end

you may have
Here’s my stab at a cross-platform implementation:

I did a quick test on Solaris (9 and 10), FreeBSD and Linux, and got
the same results in every case. (No guarantees on AIX, HP-UX, etc.)

Thanks all. I appreciate the help.

James Edward G. II

On Aug 7, 2007, at 2:38 PM, Alex Y. wrote:

-bash-3.00# stty size
It does. I was aiming at something that would work everywhere.
I think it’s fine just to special case Solaris since it’s the only
place the old code didn’t seem to hold up, for now anyway.

James Edward G. II

On Aug 7, 2007, at 3:04 PM, Daniel B. wrote:

puts “Unable to get window size”
end

Can you explain why you feel the above is “better?”

James Edward G. II

On Aug 7, 1:39 pm, James Edward G. II [email protected]
wrote:

   # A Unix savvy method to fetch the console columns, and

me too!

  `stty size`.split.map { |x| x.to_i }.reverse
end

end

I did a quick test on Solaris (9 and 10), FreeBSD and Linux, and got
the same results in every case. (No guarantees on AIX, HP-UX, etc.)

Thanks all. I appreciate the help.

James,

I think you’re better off using this snippet that Greg H. 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

[24, 80, 730, 370]

Regards,

Dan

PS - First time I think I’ve ever used IO#ioctl for anything. :slight_smile:

On Aug 7, 2007, at 4:23 PM, Daniel B. wrote:

to use the correct value of TIOCGWINSZ for Solaris:
Can you explain why you feel the above is “better?”
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().

Thanks for the advice though.

James Edward G. II

On Aug 7, 3:55 pm, James Edward G. II [email protected]
wrote:

between releases), but that’s easier than parsing stdout for each
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

On Aug 7, 2:10 pm, James Edward G. II [email protected]
wrote:

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.

Just my .02.

Regards,

Dan

Daniel B. wrote:

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?

Two older versions of Solaris…
A)
$ uname -a
SunOS sun-db-dev 5.8 Generic_117350-46 sun4u sparc SUNW,Ultra-250

[rthompso@sun-db-dev ]/export/home/rthompso
$ stty
speed 38400 baud; -parity
rows = 61; columns = 162; ypixels = 0; xpixels = 0;
swtch = ;
brkint -inpck -istrip icrnl -ixany imaxbel onlcr tab3
echo echoe echok echoctl echoke iexten

[rthompso@sun-db-dev ]/export/home/rthompso
$ stty -a
speed 38400 baud;
rows = 61; columns = 162; ypixels = 0; xpixels = 0;
csdata ?
eucw 1:0:0:0, scrw 1:0:0:0
intr = ^c; quit = ^; erase = ^?; kill = ^u;
eof = ^d; eol = ; eol2 = ; swtch = ;
start = ^q; stop = ^s; susp = ^z; dsusp = ^y;
rprnt = ^r; flush = ^o; werase = ^w; lnext = ^v;
-parenb -parodd cs8 -cstopb -hupcl cread -clocal -loblk -crtscts
-crtsxoff -parext
-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -iuclc
ixon -ixany -ixoff imaxbel
isig icanon -xcase echo echoe echok -echonl -noflsh
-tostop echoctl -echoprt echoke -defecho -flusho -pendin iexten
opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3

and

B)
$ uname -a
SunOS ender 5.6 Generic_105181-26 sun4u sparc SUNW,Ultra-30

[rthompso@ ]/home/rthompso
$ stty
speed 38400 baud; -parity
rows = 61; columns = 162; ypixels = 0; xpixels = 0;
swtch = ;
brkint -inpck -istrip icrnl -ixany imaxbel onlcr tab3
echo echoe echok echoctl echoke iexten

[rthompso@ ]/home/rthompso
$ stty -a
speed 38400 baud;
rows = 61; columns = 162; ypixels = 0; xpixels = 0;
eucw 1:0:0:0, scrw 1:0:0:0
intr = ^c; quit = ^; erase = ^?; kill = ^u;
eof = ^d; eol = ; eol2 = ; swtch = ;
start = ^q; stop = ^s; susp = ^z; dsusp = ^y;
rprnt = ^r; flush = ^o; werase = ^w; lnext = ^v;
-parenb -parodd cs8 -cstopb -hupcl cread -clocal -loblk -crtscts
-crtsxoff -parext
-ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -iuclc
ixon -ixany -ixoff imaxbel
isig icanon -xcase echo echoe echok -echonl -noflsh
-tostop echoctl -echoprt echoke -defecho -flusho -pendin iexten
opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3

Le 07 août à 21:29, James Edward G. II a écrit :

On Aug 7, 2007, at 1:54 PM, Alex Y. wrote:

On FreeBSD:

I assume the current code (using stty size) works on FreeBSD. Does
it not?

It does.

Note that stty -a is actually in the POSIX specification, meaning that
(with the regexps provided in this thread) you could use that as a
likely fallback for any unknown OS.

Fred