delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2006/01/30/10:49:48

X-Spam-Check-By: sourceware.org
Date: Mon, 30 Jan 2006 10:50:13 -0500
From: Bob Rossi <bob AT brasko DOT net>
To: cygwin AT cygwin DOT com
Cc: Chet Ramey <chet DOT ramey AT case DOT edu>
Subject: Re: readline-5.1 && CGDB
Message-ID: <20060130155013.GA13751@brasko.net>
Mail-Followup-To: cygwin AT cygwin DOT com, Chet Ramey <chet DOT ramey AT case DOT edu>
References: <20060127220812 DOT GA6931 AT brasko DOT net> <43DAA063 DOT 7070305 AT byu DOT net> <20060129041953 DOT GB30565 AT brasko DOT net> <43DE1EA1 DOT 9090506 AT byu DOT net>
Mime-Version: 1.0
In-Reply-To: <43DE1EA1.9090506@byu.net>
User-Agent: Mutt/1.5.9i
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Unsubscribe: <mailto:cygwin-unsubscribe-archive-cygwin=delorie DOT com AT cygwin DOT com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

--xHFwDpU9dbj6ez1V
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mon, Jan 30, 2006 at 07:11:45AM -0700, Eric Blake wrote:
> According to Bob Rossi on 1/28/2006 9:19 PM:
> > On Linux, something totally different happens. When I initialize
> > readline, it eventually calls tgetent, which happens to set LINES and
> > COLS to the correct size of the terminal. On cygwin this doesn't happen.
> > The call readline makes to tgetent leaves LINES and COLS alone. Then,
> > in Cygwin when I get to initscr, LINES and COLS is set to 25x80, unless
> > I set the LINES and COLUMNS environment variables before the call to
> > initscr.
> 
> http://www.die.net/doc/linux/man/man3/tgetent.3.html does not document
> that tgetent() messes with the environment, but if that is the case, you
> may be onto something.  Perhaps it really is something cygwin1.dll needs
> to patch to be more similar to linux.

I've finally produced a small test case like you asked me too. It did
take some time, but it should certainly help discover the problem. I've
attached the program.

Basically, you can run the program like './main' and that will have
readline operate on stdout, or you can run it like './main use_pty' and
that will have readline operate on a PTY that I have created. Besides
the code that opens the PTY, there is only the main function, and a
function that modifies the readline library.

If you run with the use_pty option, then ncurses thinks the terminal
size is 25x80 after the call to rl_reset_terminal. Here's the output:

    [bar AT bar-nt ~/cvs/cgdb/builddir/tmp] $ ./main.exe use_pty
    before rline_initialize LINES=0 COLS=0

	    before rl_callback LINES=0 COLS=0
	    after rl_callback LINES=75 COLS=85

	    before rl_reset_terminal LINES=75 COLS=85
	    after rl_reset_terminal LINES=25 COLS=80

    after rline_initialize LINES=25 COLS=80

    before initscr LINES=25 COLS=80
    after initscr LINES=25 COLS=80

However, if you run without that option, then ncurses thinks the terminal 
size is the correct terminal size. Here's the output:

    [bar AT bar-nt ~/cvs/cgdb/builddir/tmp] $ ./main
    before rline_initialize LINES=0 COLS=0

	    before rl_callback LINES=0 COLS=0
    (tgdb)  after rl_callback LINES=75 COLS=85

	    before rl_reset_terminal LINES=75 COLS=85
	    after rl_reset_terminal LINES=75 COLS=85

    after rline_initialize LINES=75 COLS=85

    before initscr LINES=75 COLS=85
    after initscr LINES=75 COLS=85

I've tracked down the code in readline to the line that manipulates the
LINES/COLS curses variables when initialize readline with a PTY. (This
same code does not modify the LINES/COLS variable when readline is
initialized with stdout).

The code is in terminal.c:_rl_init_terminal_io line 420 for me. It looks
like 
         tgetent_ret = tgetent (term_buffer, term);

where term is the string "dumb".

What I can't understand is, why would tgetent act differently when I
initialize readline with a created PTY, instead of stdout?

Thanks,
Bob Rossi


--xHFwDpU9dbj6ez1V
Content-Type: text/x-csrc; charset=us-ascii
Content-Disposition: attachment; filename="main.c"

#include <stdio.h>
#include <curses.h>
#include <readline/readline.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>

/*****************************************************************************
 **************************** PTY CODE ***************************************
 ****************************************************************************/
#define SLAVE_SIZE 64

static size_t strlcpy_local(char *dst, const char *src, size_t size) {
    const char *s = src;
    char *d = dst;
    size_t n = size;

    if (n)
        while (--n && (*d++ = *s++)) {}

    if (n == 0) {
        if (size)
            *d = '\0';

        while (*s++) {}
    }

    return s - src - 1;
}

int pty_open(
  int *masterfd, 
  int *slavefd, 
  char *slavename, 
  size_t slavenamesize, 
  const struct termios *slave_termios, 
  const struct winsize *slave_winsize) 
{
 char *name;

 if (!masterfd || !slavefd || !slavename || slavenamesize < 64)
  return -1;

 if ((*masterfd = open("/dev/ptmx", 2 | 0x8000)) == -1)
  return -1;

 if (grantpt(*masterfd) == -1)
 {
  close(*masterfd);
  return -1;
 }

 if (unlockpt(*masterfd) == -1)
 {
  close(*masterfd);
  return -1;
 }

 if (!(name = ptsname(*masterfd)))
 {
  close(*masterfd);
  return -1;
 }

 if (strlcpy_local(slavename, name, slavenamesize) >= slavenamesize)
 {
  close(*masterfd);
  return -1;
 }

 if ((*slavefd = open(slavename, 2 | 0x8000)) == -1)
 {
  close(*masterfd);
  return -1;
 }

 if (slave_termios && tcsetattr(*slavefd, 2, slave_termios) == -1)
 {
  close(*masterfd);
  close(*slavefd);
  return -1;
 }

 if (slave_winsize && ioctl(*slavefd, (('T' << 8) | 2), slave_winsize) == -1)
 {
  close(*masterfd);
  close(*slavefd);
  return -1;
 }

 return 0;
}

struct pty_pair 
{
  int masterfd;
  int slavefd;
  char slavename[SLAVE_SIZE];
};
typedef struct pty_pair *pty_pair_ptr;

pty_pair_ptr pty_pair_create (void)
{
  int val;
  static char local_slavename[SLAVE_SIZE];
  pty_pair_ptr ptr = (pty_pair_ptr)malloc (sizeof (struct pty_pair));
  if (!ptr)
    return NULL;

  ptr->masterfd = -1;
  ptr->slavefd = -1;
  ptr->slavename[0] = 0;

  val = pty_open (&(ptr->masterfd), &(ptr->slavefd), local_slavename, SLAVE_SIZE, NULL, NULL);
  if (val == -1)
    return NULL;   

  strncpy(ptr->slavename, local_slavename, SLAVE_SIZE);

  return ptr;
}

/*****************************************************************************
 **************************** APPLICATION CODE *******************************
 ****************************************************************************/

void
command (char *b)
{}

typedef void command_cb (char *);

int
rline_initialize (int slavefd, command_cb *command)
{
  FILE *input, *output;

  input = fdopen (slavefd, "r");
  if (!input)
    return -1;

  output = fdopen (slavefd, "w");
  if (!output)
    return -1;

  rl_instream = input;
  rl_outstream = output;

  /* Tell readline what the prompt is if it needs to put it back */
  fprintf (stderr, "\tbefore rl_callback LINES=%d COLS=%d\n", LINES, COLS);
  rl_callback_handler_install("(tgdb) ", command);
  fprintf (stderr, "\tafter rl_callback LINES=%d COLS=%d\n\n", LINES, COLS);

  /* Set the terminal type to dumb so the output of readline can be
   * understood by tgdb */
  fprintf (stderr, "\tbefore rl_reset_terminal LINES=%d COLS=%d\n", LINES, COLS);
  if (rl_reset_terminal ("dumb") == -1)
    return -1;
  fprintf (stderr, "\tafter rl_reset_terminal LINES=%d COLS=%d\n\n", LINES, COLS);

  return 0;
}

int main (int argc, char **argv)
{
#if 0
  int c;
  read(0, &c, 1);
#endif

  pty_pair_ptr pty_pair;

  pty_pair = pty_pair_create ();
  if (!pty_pair)
    return -1;

  fprintf (stderr, "before rline_initialize LINES=%d COLS=%d\n\n", LINES, COLS);

  /** 
   * If you initialize readline with stdout, everything appears to be fine.
   * However, if you initialize readline with a created slave PTY, the LINES
   * COLS are incorrect after the call to rl_reset_terminal.
   */
  if (argc == 2 && strcmp (argv[1], "use_pty") == 0)
    rline_initialize (pty_pair->slavefd, command);
  else
    rline_initialize (0, command);

  fprintf (stderr, "after rline_initialize LINES=%d COLS=%d\n\n", LINES, COLS);


  fprintf (stderr, "before initscr LINES=%d COLS=%d\n", LINES, COLS);
  initscr ();
  fprintf (stderr, "after initscr LINES=%d COLS=%d\n", LINES, COLS);
  endwin ();
  return 0;
}


--xHFwDpU9dbj6ez1V
Content-Type: text/plain; charset=us-ascii

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/
--xHFwDpU9dbj6ez1V--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019