From: Didier Verna
Subject: Getting the terminal line width ?
Date: 
Message-ID: <muxoczxwf9s.fsf@uzeb.lrde.epita.fr>
       Hello,

I would like to get the terminal line width from a standalone Common
Lisp executable. In C, I would go the IOCTL way (roughly like this):

struct winsize window;
ioctl (fileno (stream), TIOCGWINSZ, &window);
width = window.ws_col;

I'm looking for a way to do the same in Common Lisp, preferably with the
help of a portable library, or otherwise with an implementation specific
hack. I know SBCL has an sb-posix wrapper around ioctl, but I don't
quite understand how to use it.

Thanks !

-- 
Resistance is futile. You will be jazzimilated.

Scientific site:   http://www.lrde.epita.fr/~didier
Music (Jazz) site: http://www.didierverna.com

EPITA/LRDE, 14-16 rue Voltaire, 94276 Le Kremlin-Bic�tre, France
Tel. +33 (0)1 44 08 01 85       Fax. +33 (0)1 53 14 59 22

From: Kaz Kylheku
Subject: Re: Getting the terminal line width ?
Date: 
Message-ID: <20081216104514.45@gmail.com>
On 2008-11-30, Didier Verna <······@lrde.epita.fr> wrote:
>
>        Hello,
>
> I would like to get the terminal line width from a standalone Common
> Lisp executable. In C, I would go the IOCTL way (roughly like this):
>
> struct winsize window;
> ioctl (fileno (stream), TIOCGWINSZ, &window);
> width = window.ws_col;

POSIX has standardized the termios interface since 1990.  I would have
hesitated to use the raw ioctl for this fifteen years ago.  You want tcgetattr.

If you're going to sample the line width just one time on program startup, and
not respond to dynamic resizes, you might as well just obtain the value from
the COLUMNS environment variable.

Neither the kernel method nor the environment variable method will work if the
user hasn't run ``eval $(resize)'', and isn't using a virtual terminal that
communicates with the kernel behind the scenes (like a Linux virtual console or
xterm).

For a virtual terminal, the shell handles the SIGWINCH signals and updates the
COLUMNS environment variable.

So COLUMNS ought to be reliable for a one-time sample. 
From: Didier Verna
Subject: Re: Getting the terminal line width ?
Date: 
Message-ID: <muxk5akwdlq.fsf@uzeb.lrde.epita.fr>
Kaz Kylheku <········@gmail.com> wrote:

> POSIX has standardized the termios interface since 1990. I would have
> hesitated to use the raw ioctl for this fifteen years ago. You want
> tcgetattr.

  Actually, I'm resurecting code written 1994, and at that time, I
/would have/ (hesitated) ;-) Thanks for the pointer.

-- 
Resistance is futile. You will be jazzimilated.

Scientific site:   http://www.lrde.epita.fr/~didier
Music (Jazz) site: http://www.didierverna.com

EPITA/LRDE, 14-16 rue Voltaire, 94276 Le Kremlin-Bic�tre, France
Tel. +33 (0)1 44 08 01 85       Fax. +33 (0)1 53 14 59 22
From: Didier Verna
Subject: Re: Getting the terminal line width ?
Date: 
Message-ID: <muxtz9nvn9s.fsf@uzeb.lrde.epita.fr>
Kaz Kylheku <········@gmail.com> wrote:

> You want tcgetattr.

  Actually, from what I can see, tcgetattr won't help, and people still
advertise the ioctl way.

-- 
Resistance is futile. You will be jazzimilated.

Scientific site:   http://www.lrde.epita.fr/~didier
Music (Jazz) site: http://www.didierverna.com

EPITA/LRDE, 14-16 rue Voltaire, 94276 Le Kremlin-Bic�tre, France
Tel. +33 (0)1 44 08 01 85       Fax. +33 (0)1 53 14 59 22
From: David Golden
Subject: Re: Getting the terminal line width ?
Date: 
Message-ID: <ggvkid$m0p$1@aioe.org>
Didier Verna wrote:

> I know SBCL has an sb-posix wrapper around ioctl, but I
> don't quite understand how to use it.
> 
> Thanks !
> 

Bearing in mind Kaz's response, I guess part of your question is
"how do I use sb-posix stuff in sbcl to nefarious ends in general".  
Let's just treat your particular C code as a worked example, however
ill-advised, and just do a straight port.  It's rather straightforward
once you see how.  See, sb-posix is defined in terms of the "native
FFI" of sbcl, sb-alien (derived from CMUCL alien).  So the main issue
is the struct winsize, you'll need to "alienify" to work with the
sb-posix ioctl wrapper. 

On my platform, struct winsize is (termios.h):

struct winsize {
        unsigned short ws_row;
        unsigned short ws_col;
        unsigned short ws_xpixel;
        unsigned short ws_ypixel;
};

So, translate that to an alien type:

(sb-alien:define-alien-type nil
    (sb-alien:struct winsize
                     (ws_row sb-alien:unsigned-short)
                     (ws_col sb-alien:unsigned-short)
                     (ws_xpixel sb-alien:unsigned-short)
                     (ws_ypixel sb-alien:unsigned-short)))

Now you can instantiate winsize instances with just
(sb-alien:make-alien (struct winsize))

The other trick is getting the fd associated with an sbcl stream.
... Or is it? Actually, that kind of Just Works in sb-posix - if you
supply an fd-stream where an fd is expected, the fd is extracted,
at least where its possible to do so.  And right now, sbcl's underlying
fd-stream for stdin is sb-sys:*stdin*.

And of course TIOCGWINSZ is 0x5413 on my platform (ioctls.h)
(defconstant +tiocgwinsz+ #x5413)

So you now can do:

(defun termsize ()
  (let ((window (sb-alien:make-alien (struct winsize))))
    (sb-posix:ioctl sb-sys:*stdin* +tiocgwinsz+ window)
    ;; extract width (and other height)
    (values (sb-alien:slot window 'ws_col)
            (sb-alien:slot window 'ws_row))))


*  (termsize)

80
25
From: Didier Verna
Subject: Re: Getting the terminal line width ?
Date: 
Message-ID: <muxfxl8wd7f.fsf@uzeb.lrde.epita.fr>
David Golden <············@oceanfree.net> wrote:

> Bearing in mind Kaz's response, I guess part of your question is "how
> do I use sb-posix stuff in sbcl to nefarious ends in general". Let's
> just treat your particular C code as a worked example

  Thanks a lot ! Very informative.

-- 
Resistance is futile. You will be jazzimilated.

Scientific site:   http://www.lrde.epita.fr/~didier
Music (Jazz) site: http://www.didierverna.com

EPITA/LRDE, 14-16 rue Voltaire, 94276 Le Kremlin-Bic�tre, France
Tel. +33 (0)1 44 08 01 85       Fax. +33 (0)1 53 14 59 22
From: David Golden
Subject: Re: Getting the terminal line width ?
Date: 
Message-ID: <gh5qa4$7u2$1@aioe.org>
Didier Verna wrote:


>   Thanks a lot ! Very informative.
> 

but - eep, unlike my example just then - you should usually free-alien
stuff you make-alien - i.e. manual memory management like C
malloc/free.  Or see the with-alien macro for stack allocation.

Also note that sbcl includes sb-grovel, which can aid in
writing somewhat less brittle and more cross-OS alien-using code by
trying to auto-extract C constants and structure definitions for you -
see the sbcl manual.