This is the mail archive of the guile@cygnus.com mailing list for the Guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

A curses interface


Jim Blandy writes:
 > 
 > I'd like to work through Klaus's curses questions in public, because I
 > think it might help us learn:
 > 1) where the current smob interface is weak, and
 > 2) how to best explain this in the manual, since most extension
 >    writers are going to come across this at some point.
 > 
 > 
 > > Would the following work for a wrapper for the ncurses library:
 > > 
 > > long WINDOW_type = scm_make_smob_type ("WINDOW_type", sizeof (WINDOW));
 > > #define SCM2WINDOW (x) ((WINDOW *)SCM_SMOB_DATA)
 > > 
 > > scm_size_t WINDOW_free (SCM object)
 > > {
 > >   WINDOW *w;
 > >   w = SCM2WINDOW (object);
 > >   gh_defer_ints ();
 > >   delwin (w);
 > >   gh_allow_ints ();
 > >   return sizeof (WINDOW);
 > > }
 > > 
 > > 
 > > scm_set_smob_free (WINDOW_type, &WINDOW_free);
 > > 
 > > SCM WINDOW2SCM (WINDOW *w)
 > > {
 > >  SCM z;
 > >  SCM_NEWSMOB (z, WINDOW_type, w);
 > >  return z;
 > > }
 > 
 > I think this looks okay, modulo the typo that Mikael pointed out.
 > 
He also pointed out later that the return value of WINDOW_free is 
problematic, because it tells guile that memory has been freed without
guile knowing that it has been allocated earlier. 
In addition I forgot that not only the size of the WINDOW struct is
freed by delwin, but also the contents of it. Same in reverse is of 
course valid at allocation time. It's a bit complicated to calculate
it, as the amount of window content memory is modified by routines
writing to the window, and i don't know if it is portable across
curses versions to do it by hand. 
So Mikael, Greg Harvey and Marius worked out two alternatives, either
not to tell guile at all about the amount of memory allocated and
returned by exterior library routines, by setting the scm_size_t
arguments to 0, or using scm_done_malloc and scm_done_free to
tell guile explicitly about memory changes. 

 > > Or does the fact that windows may contain pointers to other windows which
 > > are subject to guile's memory administration make it impossible to use
 > > scm_make_smob?
 > 
 > The curses library, like most other C libraries, requires its users to
 > follow certain rules in the way they handle the objects it manages.
 > For example, if I call delwin(W) to delete W, then I can't use W any
 > more.  If I say V = subwin (W, ...), to make V a subwindow of W, then
 > I must call delwin (V) before I delwin (W).  And so on.
 > 
 > In C, if you violate these rules, everyone understands that your
 > program will just crash.  It's culturally acceptable.

Many perl wrappers programmers don't seem to care much either for the
consistency, including the perl curses implementation. Most Python
people instead do care. 

 > 
 > In Scheme, this is not culturally acceptable.  If you do something
 > wrong, you should get a plausible error message, and the system should
 > be left in a consistent state.

Unfortunately I remember some tough argumentation on comp.lang.scheme
where supporters of another scheme implementation (gambit???) praised
theimplementation's C callout interface as very comfortable. Marius
pointed out that this comfort is at cost of robustness. So there are
also some differences in the scheme community.
 > 
 > So when you write a Scheme interface to a C library, you are turning a
 > vulnerable interface, which trusts you not to pass it bad pointers or
 > dead objects, into a rugged, bulletproof interface which makes it
 > impossible for the caller to mung the state of the system.
 > 
 > 
 > I don't really understand your question about windows pointing to
 > other windows.  

A curses window contains a pointer to its parent window, if it has one.

 > But I think the answer is: as the author of the
 > Guile/ncurses interface, you are responsible for doing whatever is
 > necessary to turn any arbitrary sequence of Scheme-level operations on
 > Scheme curses objects into a safe sequence of C-level operations on C
 > curses objects.

Currently I don't allow explicit deletion from scheme level at all 
anymore, so only the problem of garbage-collecting referenced smobs 
remains.
 > 
 > Thus, if one window points to another, and the Scheme user deletes the
 > latter, then you're responsible for making sure things turn out okay.
 > How you handle it is up to you.  An error message is one possibility.
 > Doing extra work to make the request legal (e.g., automatically
 > deleting subwindows when a window is deleted) is another.
 > 
 > 
 > Questions to ponder:
 > 
 > If a Scheme window object gets GC'd, what should curses do with the C
 > window object?  Should it really delete the C window, or should it
 > leave it on the screen? 


 > Just because I'm not doing anything with a
 > window any more doesn't mean I want it to disappear.

So far I protect stdscr , the base window for most curses applications,
by writing the freeing function in a way that it does not do anything
when the window is stdscr. Deleting stdscr in the middle of a curses
application is dangerous. Jaffer goes the same way with his scm-curses.
 
 > 
 > If I delete a C window, and then try to write text to it, the library
 > will just crash.  At the Scheme level, such a sequence should cause an
 > error.  Your library is responsible for detecting this situation.  How
 > will you implement that behavior?

Currently I disallow explicit removal, and have the mark function 
call explicitly the mark function of the parent window. 
 > 
 > Should users be able to link Guile and your library with their own C
 > code, and manipulate windows directly in C?  If so, when they delete a
 > window, how will your library find out?  Curses probably won't tell
 > you, so you'd have to require the C code to cooperate with your
 > library.  Or just decide that people can't call certain functions
 > directly, should go through your functions instead.
 > 
I prefer the latter, i.e. C code should not interact directly with 
that of the curses module.   

Klaus Schilling

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]