Exploring terminfo

Grant Edwards grant.b.edwards at gmail.com
Fri Jan 15 16:17:22 EST 2021


On 2021-01-15, Alan Gauld via Python-list <python-list at python.org> wrote:
> On 15/01/2021 17:31, Grant Edwards wrote:
>
>>>> cur.putp(cls)
>>>> name = input("Hello, what's your name? ")
>>>>
>>>> cur.putp(bold)
>>>> print("Nice to meet you ", name)
>
>
>>>     putp(clr);
>>>     putp(bold);
>>>     printf("Enter a name: ");
>>>     fgets(line, sizeof(line),stdin);
>>>
>>>     printf("Hello %s\n", line);
>>>     exit(0);
>
>> One difference is that the name prompt is being written to stdout in
>> the C version and stderr in the Python version. But I don't see why
>> that would matter.
>
> That could make a big difference, the putp() function specifically
> states that it writes to stdout.
>
>> I suspect that the problem is that putp is writing to the libc
>> "stdout" FILE stream that's declaredin <stdio.h>. That stream
>> layer/object has buffering that is invisible to Python. 
>
> That would indeed explain it.
>
>> Now the question: is there a way to tell the curses module to flush
>> its stdout FILE stream?
>
> Indeed. But unless it's trivial it rather defeats the concept of
> using the terminfo functions to create text effects without
> diving into full curses screen control! And that was what I
> was hoping to uncover.
>
> I wonder if I can use the os module to mess with the
> file descriptors.... hmmm.

Yes, but that doesn't help. You need to flush the libc FILE *stdio not
the underlying file descriptor. Here's how you do it:


  import os,ctypes,sys,time
  
  libc = ctypes.CDLL(None, use_errno=True)
  
  import curses as cur
  cur.setupterm()
  
  bold = cur.tigetstr('bold')
  norm = cur.tigetstr('sgr0')
  cls = cur.tigetstr('clear')
  
  cur.putp(cls)
  libc.fflush(None)
  name = input("Enter your name: ")
  cur.putp(bold)
  libc.fflush(None)
  sys.stdout.write("\nNice to meet you " + name + "\n")
  cur.putp(norm);
  libc.fflush(None)
  input("Hit enter to exit")

The call to libc.fflush(None) flushes all output FILE * streams. If
you really just want to flush stdout, to flush just stdout:


  import os,ctypes,sys,time

  libc = ctypes.CDLL(None, use_errno=True)
  stdout = ctypes.c_void_p.in_dll(libc, 'stdout')

  import curses as cur
  cur.setupterm()

  bold = cur.tigetstr('bold')
  norm = cur.tigetstr('sgr0')
  cls = cur.tigetstr('clear')

  cur.putp(cls)
  libc.fflush(stdout)
  name = input("Enter your name: ")
  cur.putp(bold)
  libc.fflush(stdout)
  sys.stdout.write("\nNice to meet you " + name + "\n")
  cur.putp(norm);
  libc.fflush(stdout)
  input("Hit enter to exit")

I'd wrap cur.putp() to make it less ugly:

  import os,ctypes,sys,time

  libc = ctypes.CDLL(None, use_errno=True)
  stdout = ctypes.c_void_p.in_dll(libc, 'stdout')

  import curses as cur
  cur.setupterm()

  def putp(*args):
      sys.stderr.flush()
      sys.stdout.flush()
      cur.putp(*args)
      libc.fflush(stdout)

  bold = cur.tigetstr('bold')
  norm = cur.tigetstr('sgr0')
  cls = cur.tigetstr('clear')

  putp(cls)

  name = input("Enter your name: ")

  putp(bold)
  print("Nice to meet you",name)
  putp(norm);

  input("Hit enter to exit")



More information about the Python-list mailing list