# $Id: termsize.pl,v 1.1 2000/01/24 13:03:35 friedman Exp $

sub err
{
  my $msg = join (": ", $0, @_);
  print STDERR $msg, (substr ($msg, -1, 1) eq "\n"? "" : "\n");
  return undef;
}

sub cpp_const ($;@)
{
  return unless ($#_ > 0);

  use Symbol;
  my $sym = shift;

  my ($irh, $iwh, $orh, $owh) = (gensym, gensym, gensym, gensym);
  pipe ($irh, $iwh) || return err ("pipe", $!);
  pipe ($orh, $owh) || return err ("pipe", $!);

  if (fork == 0)
    {
      $ENV{PATH} .= ":/lib:/usr/lib";
      open (STDIN,  "<&=" . fileno ($irh)) || return err ("dup2", "stdin", $!);
      open (STDOUT, ">&=" . fileno ($owh)) || return err ("dup2", "stdout", $!);
      open (STDERR, ">/dev/null") || return err ("stderr", "/dev/null", $!);
      close ($iwh);
      close ($orh);
      exec ("cpp") || exit (1);
    }
  close ($irh);
  close ($owh);
  foreach $header (@_)
    {
      print $iwh "#include <", $header, ">\n";
    }
  print $iwh "perl_param = ", $sym, "\n";
  close ($iwh);
  my $result = undef;
  while (<$orh>)
    {
      next unless (/^perl_param = /o);
      chop;
      s/^perl_param = //o;
      # If an expression expands into a bit-shifting operation
      # like "(('T'<<8) |104)", convert 'T' to (ord 'T').
      s/('[^']')/(ord $1)/go if (/'[^']'[ \t()]*[<>][<>]/o);
      s/\(\s*\w_t\s*\*?\s*\)//go;         # get rid of (foo_t *) casts
      s/\(\s*(unsigned)*\s*(void|char|int|long)\s*\)//go; # get rid of casts
      s/sizeof\s*\(\s*struct\s*winsize\s*\)/8/go; # guess sizeof winsize
      s/sizeof\s*\(\s*struct\s*ttysize\s*\)/4/go; # guess sizeof sunos ttysize
      $result = $_;
      last;
    }
  close ($orh);
  wait;
  return $result;
}

# Returns a reference [row,col,xpixel,ypixel]
sub termsize (;$)
{
  my $fh = shift || *STDOUT;

  if (0 && !defined &TIOCGWINSZ)
    {
      foreach $ph (qw(sys/ioctl.ph sys/termios.ph ttold.ph))
        {
          eval { require "$ph" };
          last if (defined &TIOCGWINSZ);
        }
    }
  if (!defined &TIOCGWINSZ)
    {
      # Ok, either those files didn't define what we wanted or there are no
      # ph files to begin with.  Try cpp now.
      my $param = cpp_const ('TIOCGWINSZ',
                             qw(sys/ioctl.h sys/termios.h sys/ttycom.h ttold.h));
      return undef unless (defined $param);
print STDERR "param = $param\n";
      local $SIG{__WARN__} = sub { 0; };
      eval ("sub TIOCGWINSZ { $param; }")
        if (eval ("$param"));  # supress eval errors
    }

  if (defined &TIOCGWINSZ)
    {
      print STDERR "TIOCGWINSZ = ", &TIOCGWINSZ, "\n";

      -t $fh || err ("fh is not a tty");
      ioctl ($fh, &TIOCGWINSZ, $winsize='')
        || return err ("ioctl(TIOCGWINSZ)", $!);
      return [unpack ('S4', $winsize)];
    }
}

$val = termsize;
print "(row,col) = ($val->[0],$val->[1])\n";
print "(xpixel,ypixel) = ($val->[2],$val->[3])\n"
  if ($val->[2] || $val->[3]);
