ncurses 5.9 - patch 20140809
[ncurses.git] / c++ / cursesw.cc
index baae046ef20460d9b40947f503574f0ca796d5e1..16438770d47aaf178a92b0d52ddbb956efb7d407 100644 (file)
 // * this is for making emacs happy: -*-Mode: C++;-*-
+/****************************************************************************
+ * Copyright (c) 2007-2012,2014 Free Software Foundation, Inc.              *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
 
 /*
-  Copyright (C) 1989 Free Software Foundation
-  written by Eric Newton (newton@rocky.oswego.edu)
-
-  This file is part of the GNU C++ Library.  This library is free
-  software; you can redistribute it and/or modify it under the terms of
-  the GNU Library General Public License as published by the Free
-  Software Foundation; either version 2 of the License, or (at your
-  option) any later version.  This library is distributed in the hope
-  that it will be useful, but WITHOUT ANY WARRANTY; without even the
-  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-  PURPOSE.  See the GNU Library General Public License for more details.
-  You should have received a copy of the GNU Library General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-  modified by Ulrich Drepper  (drepper@karlsruhe.gmd.de)
-          and Anatoly Ivasyuk (anatoly@nick.csh.rit.edu)
-
-  modified by Juergen Pfeifer (juergen.pfeifer@gmx.net)
-*/
+ * Authors:
+ *     Thomas E. Dickey
+ *     Juergen Pfeifer
+ *
+ * The NCursesWindow class was originally based on a file written by
+ * Eric Newton, later modified by Ulrich Drepper and Anatoly Ivasyuk.
+ * However, aside from the compatible interface definition, no trace
+ * of the original code remains in this version: it consists only of
+ * changes introduced since 1995.
+ */
 
-#include "cursesw.h"
 #include "internal.h"
+#include "cursesw.h"
 
-MODULE_ID("$Id: cursesw.cc,v 1.16 1999/11/13 23:42:17 tom Exp $")
+MODULE_ID("$Id: cursesw.cc,v 1.54 2014/02/01 22:10:42 tom Exp $")
 
 #define COLORS_NEED_INITIALIZATION  -1
 #define COLORS_NOT_INITIALIZED       0
 #define COLORS_MONOCHROME            1
 #define COLORS_ARE_REALLY_THERE      2
 
+#define HaveColors() (colorInitialized == COLORS_ARE_REALLY_THERE)
+
 // declare static variables for the class
 long NCursesWindow::count = 0L;
 bool NCursesWindow::b_initialized = FALSE;
 
-#if defined(__GNUG__)
-#  ifndef _IO_va_list
-#    define _IO_va_list char *
-#  endif
-#endif
-
 int
 NCursesWindow::scanw(const char* fmt, ...)
 {
-#if defined(__GNUG__)
+    int result = ERR;
+
     va_list args;
     va_start(args, fmt);
-    char buf[BUFSIZ];
-    int result = wgetstr(w, buf);
-    if (result == OK) {
-       strstreambuf ss(buf, sizeof(buf));
-       result = ss.vscan(fmt, (_IO_va_list)args);
-    }
+    result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
     va_end(args);
+
     return result;
-#else
-    return ERR;
-#endif
 }
 
 
 int
 NCursesWindow::scanw(int y, int x, const char* fmt, ...)
 {
-#if defined(__GNUG__)
-    va_list args;
-    va_start(args, fmt);
-    char buf[BUFSIZ];
-    int result = wmove(w, y, x);
-    if (result == OK) {
-       result = wgetstr(w, buf);
-       if (result == OK) {
-           strstreambuf ss(buf, sizeof(buf));
-           result = ss.vscan(fmt, (_IO_va_list)args);
-       }
+    int result = ERR;
+
+    if (::wmove(w, y, x) != ERR) {
+       va_list args;
+       va_start(args, fmt);
+       result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
+       va_end(args);
+    }
+    return result;
+}
+
+
+int
+NCursesWindow::scanw(const char* fmt, va_list args)
+{
+    int result = ERR;
+
+    result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
+
+    return result;
+}
+
+
+int
+NCursesWindow::scanw(int y, int x, const char* fmt, va_list args)
+{
+    int result = ERR;
+
+    if (::wmove(w, y, x) != ERR) {
+       result = ::vw_scanw (w, const_cast<NCURSES_CONST char *>(fmt), args);
     }
-    va_end(args);
     return result;
-#else
-    return ERR;
-#endif
 }
 
 
@@ -90,10 +112,9 @@ NCursesWindow::printw(const char * fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
-    char buf[BUFSIZ];
-    vsprintf(buf, fmt, args);
+    int result = ::vw_printw(w, fmt, args);
     va_end(args);
-    return waddstr(w, buf);
+    return result;
 }
 
 
@@ -102,23 +123,39 @@ NCursesWindow::printw(int y, int x, const char * fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
-    int result = wmove(w, y, x);
+    int result = ::wmove(w, y, x);
     if (result == OK) {
-       char buf[BUFSIZ];
-       vsprintf(buf, fmt, args);
-       result = waddstr(w, buf);
+       result = ::vw_printw(w, fmt, args);
     }
     va_end(args);
     return result;
 }
 
 
+int
+NCursesWindow::printw(const char * fmt, va_list args)
+{
+    int result = ::vw_printw(w, fmt, args);
+    return result;
+}
+
+
+int
+NCursesWindow::printw(int y, int x, const char * fmt, va_list args)
+{
+    int result = ::wmove(w, y, x);
+    if (result == OK) {
+       result = ::vw_printw(w, fmt, args);
+    }
+    return result;
+}
+
+
 void
-NCursesWindow::init(void)
+NCursesWindow::set_keyboard(void)
 {
-    leaveok(0);
-    keypad(1);
-    meta(1);
+    keypad(TRUE);
+    meta(TRUE);
 }
 
 void
@@ -128,71 +165,74 @@ NCursesWindow::err_handler(const char *msg) const THROWS(NCursesException)
 }
 
 void
-NCursesWindow::initialize() {
-  if (!b_initialized) {
-    ::initscr();
-    b_initialized = TRUE;
-    if (colorInitialized==COLORS_NEED_INITIALIZATION) {
-      colorInitialized=COLORS_NOT_INITIALIZED;
-      useColors();
+NCursesWindow::initialize()
+{
+    if (!b_initialized) {
+       ::initscr();
+       b_initialized = TRUE;
+       if (colorInitialized == COLORS_NEED_INITIALIZATION) {
+           colorInitialized = COLORS_NOT_INITIALIZED;
+           useColors();
+       }
+       ::noecho();
+       ::cbreak();
     }
-    ::noecho();
-    ::cbreak();
-  }
 }
 
-NCursesWindow::NCursesWindow() {
-  if (!b_initialized)
+void
+NCursesWindow::constructing()
+{
     initialize();
+    ++count;
+}
+
+NCursesWindow::NCursesWindow()
+  : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
+{
+    constructing();
 
-  w = (WINDOW *)0;
-  init();
-  alloced = FALSE;
-  subwins = par = sib = 0;
-  count++;
+    w = static_cast<WINDOW *>(0);
 }
 
-NCursesWindow::NCursesWindow(int lines, int cols, int begin_y, int begin_x)
+NCursesWindow::NCursesWindow(int nlines, int ncols, int begin_y, int begin_x)
+  : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
 {
-    if (!b_initialized)
-      initialize();
+    constructing();
 
-    w = ::newwin(lines, cols, begin_y, begin_x);
+    w = ::newwin(nlines, ncols, begin_y, begin_x);
     if (w == 0) {
        err_handler("Cannot construct window");
     }
-    init();
-
-    alloced = TRUE;
-    subwins = par = sib = 0;
-    count++;
+    set_keyboard();
 }
 
-NCursesWindow::NCursesWindow(WINDOW* &window)
+NCursesWindow::NCursesWindow(WINDOW* window)
+  : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
 {
-    if (!b_initialized)
-      initialize();
-
-    w = window;
-    init();
-    alloced = FALSE;
-    subwins = par = sib = 0;
-    count++;
+    constructing();
+
+    // We used to use a reference on the "window" parameter, but we cannot do
+    // that with an opaque pointer (see NCURSES_OPAQUE).  If the parameter was
+    // "::stdscr", that is first set via the "constructing() call, and is null
+    // up to that point.  So we allow a null pointer here as meaning the "same"
+    // as "::stdscr".
+    w = window ? window : ::stdscr;
+    set_keyboard();
 }
 
-NCursesWindow::NCursesWindow(NCursesWindow& win, int l, int c,
+NCursesWindow::NCursesWindow(NCursesWindow& win, int ny, int nx,
                             int begin_y, int begin_x, char absrel)
+  : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
 {
-    if (absrel == 'a') { // absolute origin
+    constructing();
+    if (absrel == 'a') {       // absolute origin
        begin_y -= win.begy();
        begin_x -= win.begx();
     }
 
-    // Even though we treat subwindows as a tree, the standard curses
-    // library needs the `subwin' call to link to the parent in
-    // order to correctly perform refreshes, etc.
-    // Friendly enough, this also works for pads.
-    w = ::derwin(win.w, l, c, begin_y, begin_x);
+    // Link this window into its parent's list of subwindows.
+    // We use derwin(), since this also works for pads.
+    w = ::derwin(win.w, ny, nx, begin_y, begin_x);
     if (w == 0) {
        err_handler("Cannot construct subwindow");
     }
@@ -200,40 +240,40 @@ NCursesWindow::NCursesWindow(NCursesWindow& win, int l, int c,
     par = &win;
     sib = win.subwins;
     win.subwins = this;
-    subwins = 0;
-    alloced = TRUE;
-    count++;
 }
 
 NCursesWindow::NCursesWindow(NCursesWindow& win,
                                bool do_box NCURSES_PARAM_INIT(TRUE))
+  : w(0), alloced(TRUE), par(0), subwins(0), sib(0)
 {
-  w = :: derwin(win.w,win.height()-2,win.width()-2,1,1);
-  if (w == 0) {
-    err_handler("Cannot construct subwindow");
-  }
+    constructing();
+    int myHeight = win.height();
+    int myWidth  = win.width();
+    w = :: derwin(win.w, myHeight - 2, myWidth - 2, 1, 1);
+    if (w == 0) {
+       err_handler("Cannot construct subwindow");
+    }
 
-  par = &win;
-  sib = win.subwins;
-  win.subwins = this;
-  subwins = 0;
-  alloced = TRUE;
-  count++;
+    par = &win;
+    sib = win.subwins;
+    win.subwins = this;
+    subwins = 0;
 
-  if (do_box) {
-    win.box();
-    win.touchwin();
-  }
+    if (do_box) {
+       win.box();
+       win.touchwin();
+    }
 }
 
-NCursesWindow NCursesWindow::Clone() {
-  WINDOW *d = ::dupwin(w);
-  NCursesWindow W(d);
-  W.subwins = subwins;
-  W.sib = sib;
-  W.par = par;
-  W.alloced = alloced;
-  return W;
+NCursesWindow NCursesWindow::Clone()
+{
+    WINDOW *d = ::dupwin(w);
+    NCursesWindow W(d);
+    W.subwins = subwins;
+    W.sib = sib;
+    W.par = par;
+    W.alloced = alloced;
+    return W;
 }
 
 typedef int (*RIPOFFINIT)(NCursesWindow&);
@@ -241,60 +281,65 @@ static RIPOFFINIT R_INIT[5];       // There can't be more
 static int r_init_idx   = 0;
 static RIPOFFINIT* prip = R_INIT;
 
-extern "C" int _nc_ripoffline(int,int (*init)(WINDOW*,int));
-
-NCursesWindow::NCursesWindow(WINDOW *win, int cols) {
-  w = win;
-  assert((w->_maxx+1)==cols);
-  alloced = FALSE;
-  subwins = par = sib = 0;
+NCursesWindow::NCursesWindow(WINDOW *win, int ncols)
+  : w(0), alloced(FALSE), par(0), subwins(0), sib(0)
+{
+    (void) ncols;
+    initialize();
+    w = win;
 }
 
-int NCursesWindow::ripoff_init(WINDOW *w, int cols)
+int _nc_xx_ripoff_init(WINDOW *w, int ncols)
 {
-  int res = ERR;
+    (void) ncols;
+    int res = ERR;
 
-  RIPOFFINIT init = *prip++;
-  if (init) {
-    NCursesWindow* W = new NCursesWindow(w,cols);
-    res = init(*W);
-  }
-  return res;
+    RIPOFFINIT init = *prip++;
+    if (init) {
+       res = init(*(new NCursesWindow(w,ncols)));
+    }
+    return res;
 }
 
 int NCursesWindow::ripoffline(int ripoff_lines,
-                             int (*init)(NCursesWindow& win)) {
-  int code = ::_nc_ripoffline(ripoff_lines,ripoff_init);
-  if (code==OK && init && ripoff_lines) {
-    R_INIT[r_init_idx++] = init;
-  }
-  return code;
+                             int (*init)(NCursesWindow& win))
+{
+    int code = ::_nc_ripoffline(ripoff_lines,_nc_xx_ripoff_init);
+    if (code == OK && init && ripoff_lines) {
+       R_INIT[r_init_idx++] = init;
+    }
+    return code;
 }
 
 bool
-NCursesWindow::isDescendant(NCursesWindow& win) {
-  for (NCursesWindow* p = subwins; p != NULL; p = p->sib) {
-    if (p==&win)
-      return TRUE;
-    else {
-      if (p->isDescendant(win))
-       return TRUE;
+NCursesWindow::isDescendant(NCursesWindow& win)
+{
+    bool result = FALSE;
+
+    for (NCursesWindow* p = subwins; p != NULL; p = p->sib) {
+       if (p == &win || p->isDescendant(win)) {
+           result = TRUE;
+           break;
+       }
     }
-  }
-  return FALSE;
+    return result;
 }
 
 void
 NCursesWindow::kill_subwindows()
 {
-    for (NCursesWindow* p = subwins; p != 0; p = p->sib) {
+    NCursesWindow* p = subwins;
+
+    subwins = 0;
+    while (p != 0) {
+       NCursesWindow* q = p->sib;
        p->kill_subwindows();
        if (p->alloced) {
            if (p->w != 0)
                ::delwin(p->w);
-           p->alloced = FALSE;
        }
-       p->w = 0; // cause a run-time error if anyone attempts to use...
+       delete p;
+       p = q;
     }
 }
 
@@ -303,36 +348,34 @@ NCursesWindow::~NCursesWindow()
 {
     kill_subwindows();
 
-    if (par != 0) {  // Snip us from the parent's list of subwindows.
-       NCursesWindow * win = par->subwins;
-       NCursesWindow * trail = 0;
-       for (;;) {
-           if (win == 0)
-               break;
-           else if (win == this) {
-               if (trail != 0)
-                   trail->sib = win->sib;
-               else
-                   par->subwins = win->sib;
+    if (par != 0) {
+       // Remove this window from the parent's list of subwindows.
+       NCursesWindow * next = par->subwins;
+       NCursesWindow * prev = 0;
+       while (next != 0) {
+           if (next == this) {
+               if (prev != 0) {
+                   prev->sib = next->sib;
+               } else {
+                   par->subwins = next->sib;
+               }
                break;
-           } else {
-               trail = win;
-               win = win->sib;
            }
+           prev = next;
+           next = next->sib;
        }
     }
 
     if (alloced && w != 0)
-       delwin(w);
+       ::delwin(w);
 
     if (alloced) {
-      --count;
-      if (count == 0) {
-       ::endwin();
-      }
-      else if (count < 0) { // cannot happen!
-       err_handler("Too many windows destroyed");
-      }
+       --count;
+       if (count == 0) {
+           ::endwin();
+       } else if (count < 0) { // cannot happen!
+           err_handler("Too many windows destroyed");
+       }
     }
 }
 
@@ -345,90 +388,82 @@ void
 NCursesWindow::useColors(void)
 {
     if (colorInitialized == COLORS_NOT_INITIALIZED) {
-      if (b_initialized) {
-       if (::has_colors()) {
-         ::start_color();
-         colorInitialized = COLORS_ARE_REALLY_THERE;
+       if (b_initialized) {
+           if (::has_colors()) {
+               ::start_color();
+               colorInitialized = COLORS_ARE_REALLY_THERE;
+           } else {
+               colorInitialized = COLORS_MONOCHROME;
+           }
+       } else {
+           colorInitialized = COLORS_NEED_INITIALIZATION;
        }
-       else
-         colorInitialized = COLORS_MONOCHROME;
-      }
-      else
-       colorInitialized = COLORS_NEED_INITIALIZATION;
     }
 }
 
-short
-NCursesWindow::getcolor(int getback) const
+NCURSES_PAIRS_T
+NCursesWindow::getPair() const
 {
-    short fore, back;
+    return static_cast<NCURSES_PAIRS_T>(PAIR_NUMBER(getattrs(w)));
+}
 
-    if (colorInitialized==COLORS_ARE_REALLY_THERE) {
-      if (pair_content((short)PAIR_NUMBER(w->_attrs), &fore, &back))
-       err_handler("Can't get color pair");
-    }
-    else {
-      // Monochrome means white on black
-      back = COLOR_BLACK;
-      fore = COLOR_WHITE;
+NCURSES_COLOR_T
+NCursesWindow::getcolor(int getback) const
+{
+    NCURSES_COLOR_T fore, back;
+
+    if (HaveColors()) {
+       if (::pair_content(getPair(), &fore, &back) == ERR)
+           err_handler("Can't get color pair");
+    } else {
+       // Monochrome means white on black
+       back = COLOR_BLACK;
+       fore = COLOR_WHITE;
     }
     return getback ? back : fore;
 }
 
 int NCursesWindow::NumberOfColors()
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return COLORS;
-  else
-    return 1; // monochrome (actually there are two ;-)
+    return (HaveColors()) ? COLORS : 1;
 }
 
-short
+NCURSES_PAIRS_T
 NCursesWindow::getcolor() const
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return PAIR_NUMBER(w->_attrs);
-  else
-    return 0; // we only have pair zero
+    return (HaveColors()) ? getPair() : 0;
 }
 
 int
-NCursesWindow::setpalette(short fore, short back, short pair)
+NCursesWindow::setpalette(NCURSES_COLOR_T fore, NCURSES_COLOR_T back, NCURSES_PAIRS_T pair)
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return init_pair(pair, fore, back);
-  else
-    return OK;
+    return (HaveColors()) ? ::init_pair(pair, fore, back) : OK;
 }
 
 int
-NCursesWindow::setpalette(short fore, short back)
+NCursesWindow::setpalette(NCURSES_COLOR_T fore, NCURSES_COLOR_T back)
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE)
-    return setpalette(fore, back, (short)PAIR_NUMBER(w->_attrs));
-  else
-    return OK;
+    return setpalette(fore, back, getPair());
 }
 
 
 int
-NCursesWindow::setcolor(short pair)
+NCursesWindow::setcolor(NCURSES_PAIRS_T pair)
 {
-  if (colorInitialized==COLORS_ARE_REALLY_THERE) {
-    if ((pair < 1) || (pair > COLOR_PAIRS))
-      err_handler("Can't set color pair");
+    if (HaveColors()) {
+       if ((pair < 1) || (pair > COLOR_PAIRS))
+           err_handler("Can't set color pair");
 
-    attroff(A_COLOR);
-    attrset(COLOR_PAIR(pair));
-  }
-  return OK;
+       attroff(A_COLOR);
+       attrset(COLOR_PAIR(pair));
+    }
+    return OK;
 }
 
-#ifdef HAVE_HAS_KEY
-extern "C" int _nc_has_mouse(void);
-
-bool NCursesWindow::has_mouse() const {
-  return ((::has_key(KEY_MOUSE) || ::_nc_has_mouse())
-         ? TRUE : FALSE);
+#if HAVE_HAS_KEY
+bool NCursesWindow::has_mouse() const
+{
+    return ((::has_key(KEY_MOUSE) || ::has_mouse())
+            ? TRUE : FALSE);
 }
 #endif