]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - form/frm_driver.c
ncurses 6.4 - patch 20240414
[ncurses.git] / form / frm_driver.c
index 5a8f6b08cc9df1dbd9601f38bd449a5ab328f21a..75656d69ea2a44b00136754cb5cbcf183c4599a8 100644 (file)
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 1998-2008,2009 Free Software Foundation, Inc.              *
+ * Copyright 2018-2020,2021 Thomas E. Dickey                                *
+ * Copyright 1998-2016,2017 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            *
@@ -32,7 +33,7 @@
 
 #include "form.priv.h"
 
-MODULE_ID("$Id: frm_driver.c,v 1.96 2009/12/12 23:19:29 tom Exp $")
+MODULE_ID("$Id: frm_driver.c,v 1.135 2021/09/01 23:34:01 tom Exp $")
 
 /*----------------------------------------------------------------------------
   This is the core module of the form library. It contains the majority
@@ -99,9 +100,9 @@ Perhaps at some time we will make this configurable at runtime.
 #define GROW_IF_NAVIGATE (1)
 
 #if USE_WIDEC_SUPPORT
-#define myADDNSTR(w, s, n) wadd_wchnstr(w, s, n)
-#define myINSNSTR(w, s, n) wins_wchnstr(w, s, n)
-#define myINNSTR(w, s, n)  fix_wchnstr(w, s, n)
+#define myADDNSTR(w, s, n) wide_waddnstr(w, s, n)
+#define myINSNSTR(w, s, n) wide_winsnstr(w, s, n)
+#define myINNSTR(w, s, n)  wide_winnstr(w, s, n)
 #define myWCWIDTH(w, y, x) cell_width(w, y, x)
 #else
 #define myADDNSTR(w, s, n) waddnstr(w, s, n)
@@ -130,34 +131,34 @@ static int FE_Delete_Previous(FORM *);
 /* Calculate the position of a single row in a field buffer */
 #define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
 
-/* Calculate start address for the fields buffer# N */
+/* Calculate start address for the field's buffer# N */
 #define Address_Of_Nth_Buffer(field,N) \
   ((field)->buf + (N)*(1+Buffer_Length(field)))
 
-/* Calculate the start address of the row in the fields specified buffer# N */
+/* Calculate the start address of the row in the field's specified buffer# N */
 #define Address_Of_Row_In_Nth_Buffer(field,N,row) \
   (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
 
-/* Calculate the start address of the row in the fields primary buffer */
+/* Calculate the start address of the row in the field's primary buffer */
 #define Address_Of_Row_In_Buffer(field,row) \
   Address_Of_Row_In_Nth_Buffer(field,0,row)
 
-/* Calculate the start address of the row in the forms current field
+/* Calculate the start address of the row in the form's current field
    buffer# N */
 #define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
    Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
 
-/* Calculate the start address of the row in the forms current field
+/* Calculate the start address of the row in the form's current field
    primary buffer */
 #define Address_Of_Current_Row_In_Buffer(form) \
    Address_Of_Current_Row_In_Nth_Buffer(form,0)
 
-/* Calculate the address of the cursor in the forms current field
+/* Calculate the address of the cursor in the form's current field
    primary buffer */
 #define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
    (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
 
-/* Calculate the address of the cursor in the forms current field
+/* Calculate the address of the cursor in the form's current field
    buffer# N */
 #define Address_Of_Current_Position_In_Buffer(form) \
   Address_Of_Current_Position_In_Nth_Buffer(form,0)
@@ -172,29 +173,30 @@ static int FE_Delete_Previous(FORM *);
    instead of a derived window because it contains invisible parts.
    This is true for non-public fields and for scrollable fields. */
 #define Has_Invisible_Parts(field)     \
-  (!((field)->opts & O_PUBLIC)      || \
+  (!(Field_Has_Option(field, O_PUBLIC)) || \
    Is_Scroll_Field(field))
 
 /* Logic to decide whether or not a field needs justification */
 #define Justification_Allowed(field)        \
    (((field)->just != NO_JUSTIFICATION)  && \
     (Single_Line_Field(field))           && \
-    (((field)->dcols == (field)->cols)   && \
-    ((field)->opts & O_STATIC))             )
+    ((Field_Has_Option(field, O_STATIC)  && \
+     ((field)->dcols == (field)->cols))  || \
+    Field_Has_Option(field, O_DYNAMIC_JUSTIFY)))
 
 /* Logic to determine whether or not a dynamic field may still grow */
 #define Growable(field) ((field)->status & _MAY_GROW)
 
-/* Macro to set the attributes for a fields window */
+/* Macro to set the attributes for a field's window */
 #define Set_Field_Window_Attributes(field,win) \
-(  wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
-   (void) wattrset((win),(field)->fore) )
+(  wbkgdset((win),(chtype)((chtype)((field)->pad) | (field)->back)), \
+   (void) wattrset((win), (int)(field)->fore) )
 
 /* Logic to decide whether or not a field really appears on the form */
 #define Field_Really_Appears(field)         \
   ((field->form)                          &&\
    (field->form->status & _POSTED)        &&\
-   (field->opts & O_VISIBLE)              &&\
+   (Field_Has_Option(field, O_VISIBLE))   &&\
    (field->page == field->form->curpage))
 
 /* Logic to determine whether or not we are on the first position in the
@@ -215,10 +217,10 @@ static FIELD_CELL myZEROS;
 static void
 check_pos(FORM *form, int lineno)
 {
-  int y, x;
-
   if (form && form->w)
     {
+      int y, x;
+
       getyx(form->w, y, x);
       if (y != form->currow || x != form->curcol)
        {
@@ -238,15 +240,36 @@ check_pos(FORM *form, int lineno)
   Wide-character special functions
   --------------------------------------------------------------------------*/
 #if USE_WIDEC_SUPPORT
-/* like winsnstr */
+/* add like waddnstr, but using cchar_t* rather than char*
+ */
+static int
+wide_waddnstr(WINDOW *w, const cchar_t *s, int n)
+{
+  int rc = OK;
+
+  while (n-- > 0)
+    {
+      if ((rc = wadd_wch(w, s)) != OK)
+       break;
+      ++s;
+    }
+  return rc;
+}
+
+/* insert like winsnstr, but using cchar_t* rather than char*
+ *
+ * X/Open Curses has no close equivalent; inserts are done only with wchar_t
+ * strings.
+ */
 static int
-wins_wchnstr(WINDOW *w, cchar_t *s, int n)
+wide_winsnstr(WINDOW *w, const cchar_t *s, int n)
 {
   int code = ERR;
-  int y, x;
 
   while (n-- > 0)
     {
+      int y, x;
+
       getyx(w, y, x);
       if ((code = wins_wch(w, s++)) != OK)
        break;
@@ -256,11 +279,13 @@ wins_wchnstr(WINDOW *w, cchar_t *s, int n)
   return code;
 }
 
-/* win_wchnstr is inconsistent with winnstr, since it returns OK rather than
- * the number of items transferred.
+/* retrieve like winnstr, but using cchar_t*, rather than char*.
+ *
+ * X/Open Curses' closest equivalent, win_wchnstr(), is inconsistent with
+ * winnstr(), since it returns OK rather than the number of items transferred.
  */
 static int
-fix_wchnstr(WINDOW *w, cchar_t *s, int n)
+wide_winnstr(WINDOW *w, cchar_t *s, int n)
 {
   int x;
 
@@ -487,7 +512,6 @@ Buffer_To_Window(const FIELD *field, WINDOW *win)
 {
   int width, height;
   int y, x;
-  int len;
   int row;
   FIELD_CELL *pBuffer;
 
@@ -501,6 +525,8 @@ Buffer_To_Window(const FIELD *field, WINDOW *win)
        row < height;
        row++, pBuffer += width)
     {
+      int len;
+
       if ((len = (int)(After_End_Of_Data(pBuffer, width) - pBuffer)) > 0)
        {
          wmove(win, row, 0);
@@ -524,7 +550,7 @@ Buffer_To_Window(const FIELD *field, WINDOW *win)
 |
 |   Return Values :  -
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(void)
+FORM_EXPORT(void)
 _nc_get_fieldbuffer(FORM *form, FIELD *field, FIELD_CELL *buf)
 {
   int pad;
@@ -601,8 +627,8 @@ Synchronize_Buffer(FORM *form)
 {
   if (form->status & _WINDOW_MODIFIED)
     {
-      form->status &= ~_WINDOW_MODIFIED;
-      form->status |= _FCHECK_REQUIRED;
+      ClrStatus(form, _WINDOW_MODIFIED);
+      SetStatus(form, _FCHECK_REQUIRED);
       Window_To_Buffer(form, form->current);
       wmove(form->w, form->currow, form->curcol);
     }
@@ -653,7 +679,7 @@ Field_Grown(FIELD *field, int amount)
            growth = Minimum(field->maxgrow - field->dcols, growth);
          field->dcols += growth;
          if (field->dcols == field->maxgrow)
-           field->status &= ~_MAY_GROW;
+           ClrStatus(field, _MAY_GROW);
        }
       else
        {
@@ -662,7 +688,7 @@ Field_Grown(FIELD *field, int amount)
            growth = Minimum(field->maxgrow - field->drows, growth);
          field->drows += growth;
          if (field->drows == field->maxgrow)
-           field->status &= ~_MAY_GROW;
+           ClrStatus(field, _MAY_GROW);
        }
       /* drows, dcols changed, so we get really the new buffer length */
       new_buflen = Buffer_Length(field);
@@ -674,7 +700,7 @@ Field_Grown(FIELD *field, int amount)
          field->drows = old_drows;
          if ((single_line_field && (field->dcols != field->maxgrow)) ||
              (!single_line_field && (field->drows != field->maxgrow)))
-           field->status |= _MAY_GROW;
+           SetStatus(field, _MAY_GROW);
        }
       else
        {
@@ -682,8 +708,6 @@ Field_Grown(FIELD *field, int amount)
           * realloc().
           */
          int i, j;
-         FIELD_CELL *old_bp;
-         FIELD_CELL *new_bp;
 
          result = TRUE;        /* allow sharing of recovery on failure */
 
@@ -691,8 +715,9 @@ Field_Grown(FIELD *field, int amount)
          field->buf = newbuf;
          for (i = 0; i <= field->nbuf; i++)
            {
-             new_bp = Address_Of_Nth_Buffer(field, i);
-             old_bp = oldbuf + i * (1 + old_buflen);
+             FIELD_CELL *new_bp = Address_Of_Nth_Buffer(field, i);
+             FIELD_CELL *old_bp = oldbuf + i * (1 + old_buflen);
+
              for (j = 0; j < old_buflen; ++j)
                new_bp[j] = old_bp[j];
              while (j < new_buflen)
@@ -753,7 +778,7 @@ Field_Grown(FIELD *field, int amount)
                   (field->dcols != field->maxgrow)) ||
                  (!single_line_field &&
                   (field->drows != field->maxgrow)))
-               field->status |= _MAY_GROW;
+               SetStatus(field, _MAY_GROW);
              free(newbuf);
            }
        }
@@ -802,7 +827,7 @@ Field_encloses(FIELD *field, int ry, int rx)
 |                    E_SYSTEM_ERROR    - form has no current field or
 |                                        field-window
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 _nc_Position_Form_Cursor(FORM *form)
 {
   FIELD *field;
@@ -836,18 +861,20 @@ _nc_Position_Form_Cursor(FORM *form)
 |   Facility      :  libnform
 |   Function      :  int _nc_Refresh_Current_Field(FORM * form)
 |
-|   Description   :  Propagate the changes in the fields window to the
+|   Description   :  Propagate the changes in the field's window to the
 |                    window of the form.
 |
 |   Return Values :  E_OK              - on success
 |                    E_BAD_ARGUMENT    - invalid form pointer
 |                    E_SYSTEM_ERROR    - general error
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+static bool move_after_insert = TRUE;
+FORM_EXPORT(int)
 _nc_Refresh_Current_Field(FORM *form)
 {
   WINDOW *formwin;
   FIELD *field;
+  bool is_public;
 
   T((T_CALLED("_nc_Refresh_Current_Field(%p)"), (void *)form));
 
@@ -860,102 +887,106 @@ _nc_Refresh_Current_Field(FORM *form)
   field = form->current;
   formwin = Get_Form_Window(form);
 
-  if (field->opts & O_PUBLIC)
+  is_public = Field_Has_Option(field, O_PUBLIC);
+
+  if (Is_Scroll_Field(field))
     {
-      if (Is_Scroll_Field(field))
+      /* Again, in this case the fieldwin isn't derived from formwin,
+         so we have to perform a copy operation. */
+      if (Single_Line_Field(field))
        {
-         /* Again, in this case the fieldwin isn't derived from formwin,
-            so we have to perform a copy operation. */
-         if (Single_Line_Field(field))
+         /* horizontal scrolling */
+         if (form->curcol < form->begincol)
+           form->begincol = form->curcol;
+         else
            {
-             /* horizontal scrolling */
-             if (form->curcol < form->begincol)
-               form->begincol = form->curcol;
-             else
-               {
-                 if (form->curcol >= (form->begincol + field->cols))
-                   form->begincol = form->curcol - field->cols + 1;
-               }
-             copywin(form->w,
-                     formwin,
-                     0,
-                     form->begincol,
-                     field->frow,
-                     field->fcol,
-                     field->frow,
-                     field->cols + field->fcol - 1,
-                     0);
+             if (form->curcol >= (form->begincol + field->cols))
+               form->begincol = form->curcol - field->cols
+                 + (move_after_insert ? 1 : 0);
            }
-         else
+         if (is_public)
+           copywin(form->w,
+                   formwin,
+                   0,
+                   form->begincol,
+                   field->frow,
+                   field->fcol,
+                   field->frow,
+                   field->cols + field->fcol - 1,
+                   0);
+       }
+      else
+       {
+         /* A multi-line, i.e. vertical scrolling field */
+         int first_modified_row, first_unmodified_row;
+
+         if (field->drows > field->rows)
            {
-             /* A multi-line, i.e. vertical scrolling field */
-             int row_after_bottom, first_modified_row, first_unmodified_row;
+             int row_after_bottom = form->toprow + field->rows;
 
-             if (field->drows > field->rows)
+             if (form->currow < form->toprow)
                {
-                 row_after_bottom = form->toprow + field->rows;
-                 if (form->currow < form->toprow)
-                   {
-                     form->toprow = form->currow;
-                     field->status |= _NEWTOP;
-                   }
-                 if (form->currow >= row_after_bottom)
-                   {
-                     form->toprow = form->currow - field->rows + 1;
-                     field->status |= _NEWTOP;
-                   }
-                 if (field->status & _NEWTOP)
-                   {
-                     /* means we have to copy whole range */
-                     first_modified_row = form->toprow;
-                     first_unmodified_row = first_modified_row + field->rows;
-                     field->status &= ~_NEWTOP;
-                   }
-                 else
-                   {
-                     /* we try to optimize : finding the range of touched
-                        lines */
-                     first_modified_row = form->toprow;
-                     while (first_modified_row < row_after_bottom)
-                       {
-                         if (is_linetouched(form->w, first_modified_row))
-                           break;
-                         first_modified_row++;
-                       }
-                     first_unmodified_row = first_modified_row;
-                     while (first_unmodified_row < row_after_bottom)
-                       {
-                         if (!is_linetouched(form->w, first_unmodified_row))
-                           break;
-                         first_unmodified_row++;
-                       }
-                   }
+                 form->toprow = form->currow;
+                 SetStatus(field, _NEWTOP);
                }
-             else
+             if (form->currow >= row_after_bottom)
+               {
+                 form->toprow = form->currow - field->rows + 1;
+                 SetStatus(field, _NEWTOP);
+               }
+             if (field->status & _NEWTOP)
                {
+                 /* means we have to copy whole range */
                  first_modified_row = form->toprow;
                  first_unmodified_row = first_modified_row + field->rows;
+                 ClrStatus(field, _NEWTOP);
+               }
+             else
+               {
+                 /* we try to optimize : finding the range of touched
+                    lines */
+                 first_modified_row = form->toprow;
+                 while (first_modified_row < row_after_bottom)
+                   {
+                     if (is_linetouched(form->w, first_modified_row))
+                       break;
+                     first_modified_row++;
+                   }
+                 first_unmodified_row = first_modified_row;
+                 while (first_unmodified_row < row_after_bottom)
+                   {
+                     if (!is_linetouched(form->w, first_unmodified_row))
+                       break;
+                     first_unmodified_row++;
+                   }
                }
-             if (first_unmodified_row != first_modified_row)
-               copywin(form->w,
-                       formwin,
-                       first_modified_row,
-                       0,
-                       field->frow + first_modified_row - form->toprow,
-                       field->fcol,
-                       field->frow + first_unmodified_row - form->toprow - 1,
-                       field->cols + field->fcol - 1,
-                       0);
            }
-         wsyncup(formwin);
-       }
-      else
-       {
-         /* if the field-window is simply a derived window, i.e. contains no
-          * invisible parts, the whole thing is trivial
-          */
-         wsyncup(form->w);
+         else
+           {
+             first_modified_row = form->toprow;
+             first_unmodified_row = first_modified_row + field->rows;
+           }
+         if (first_unmodified_row != first_modified_row && is_public)
+           copywin(form->w,
+                   formwin,
+                   first_modified_row,
+                   0,
+                   field->frow + first_modified_row - form->toprow,
+                   field->fcol,
+                   field->frow + first_unmodified_row - form->toprow - 1,
+                   field->cols + field->fcol - 1,
+                   0);
        }
+      if (is_public)
+       wsyncup(formwin);
+    }
+  else
+    {
+      /* if the field-window is simply a derived window, i.e. contains no
+       * invisible parts, the whole thing is trivial
+       */
+      if (is_public)
+       wsyncup(form->w);
     }
   untouchwin(form->w);
   returnCode(_nc_Position_Form_Cursor(form));
@@ -976,28 +1007,32 @@ Perform_Justification(FIELD *field, WINDOW *win)
 {
   FIELD_CELL *bp;
   int len;
-  int col = 0;
 
-  bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
+  bp = (Field_Has_Option(field, O_NO_LEFT_STRIP)
+       ? field->buf
+       : Get_Start_Of_Data(field->buf, Buffer_Length(field)));
   len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
 
   if (len > 0)
     {
-      assert(win && (field->drows == 1) && (field->dcols == field->cols));
+      int col = 0;
 
-      switch (field->just)
-       {
-       case JUSTIFY_LEFT:
-         break;
-       case JUSTIFY_CENTER:
-         col = (field->cols - len) / 2;
-         break;
-       case JUSTIFY_RIGHT:
-         col = field->cols - len;
-         break;
-       default:
-         break;
-       }
+      assert(win && (field->drows == 1));
+
+      if (field->cols - len >= 0)
+       switch (field->just)
+         {
+         case JUSTIFY_LEFT:
+           break;
+         case JUSTIFY_CENTER:
+           col = (field->cols - len) / 2;
+           break;
+         case JUSTIFY_RIGHT:
+           col = field->cols - len;
+           break;
+         default:
+           break;
+         }
 
       wmove(win, 0, col);
       myADDNSTR(win, bp, len);
@@ -1019,9 +1054,14 @@ static void
 Undo_Justification(FIELD *field, WINDOW *win)
 {
   FIELD_CELL *bp;
+  int y, x;
   int len;
 
-  bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
+  getyx(win, y, x);
+
+  bp = (Field_Has_Option(field, O_NO_LEFT_STRIP)
+       ? field->buf
+       : Get_Start_Of_Data(field->buf, Buffer_Length(field)));
   len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
 
   if (len > 0)
@@ -1030,6 +1070,7 @@ Undo_Justification(FIELD *field, WINDOW *win)
       wmove(win, 0, 0);
       myADDNSTR(win, bp, len);
     }
+  wmove(win, y, x);
 }
 
 /*---------------------------------------------------------------------------
@@ -1111,27 +1152,27 @@ Display_Or_Erase_Field(FIELD *field, bool bEraseFlag)
     return E_SYSTEM_ERROR;
   else
     {
-      if (field->opts & O_VISIBLE)
+      if (Field_Has_Option(field, O_VISIBLE))
        {
          Set_Field_Window_Attributes(field, win);
        }
       else
        {
-         (void)wattrset(win, WINDOW_ATTRS(fwin));
+         (void)wattrset(win, (int)WINDOW_ATTRS(fwin));
        }
       werase(win);
     }
 
   if (!bEraseFlag)
     {
-      if (field->opts & O_PUBLIC)
+      if (Field_Has_Option(field, O_PUBLIC))
        {
          if (Justification_Allowed(field))
            Perform_Justification(field, win);
          else
            Buffer_To_Window(field, win);
        }
-      field->status &= ~_NEWTOP;
+      ClrStatus(field, _NEWTOP);
     }
   wsyncup(win);
   delwin(win);
@@ -1170,18 +1211,18 @@ Synchronize_Field(FIELD *field)
          form->currow = form->curcol = form->toprow = form->begincol = 0;
          werase(form->w);
 
-         if ((field->opts & O_PUBLIC) && Justification_Allowed(field))
+         if ((Field_Has_Option(field, O_PUBLIC)) && Justification_Allowed(field))
            Undo_Justification(field, form->w);
          else
            Buffer_To_Window(field, form->w);
 
-         field->status |= _NEWTOP;
+         SetStatus(field, _NEWTOP);
          res = _nc_Refresh_Current_Field(form);
        }
       else
        res = Display_Field(field);
     }
-  field->status |= _CHANGED;
+  SetStatus(field, _CHANGED);
   return (res);
 }
 
@@ -1202,7 +1243,6 @@ Synchronize_Linked_Fields(FIELD *field)
 {
   FIELD *linked_field;
   int res = E_OK;
-  int syncres;
 
   if (!field)
     return (E_BAD_ARGUMENT);
@@ -1211,9 +1251,11 @@ Synchronize_Linked_Fields(FIELD *field)
     return (E_SYSTEM_ERROR);
 
   for (linked_field = field->link;
-       linked_field != field;
+       (linked_field != field) && (linked_field != 0);
        linked_field = linked_field->link)
     {
+      int syncres;
+
       if (((syncres = Synchronize_Field(linked_field)) != E_OK) &&
          (res == E_OK))
        res = syncres;
@@ -1225,7 +1267,7 @@ Synchronize_Linked_Fields(FIELD *field)
 |   Facility      :  libnform
 |   Function      :  int _nc_Synchronize_Attributes(FIELD * field)
 |
-|   Description   :  If a fields visual attributes have changed, this
+|   Description   :  If a field's visual attributes have changed, this
 |                    routine is called to propagate those changes to the
 |                    screen.
 |
@@ -1233,12 +1275,11 @@ Synchronize_Linked_Fields(FIELD *field)
 |                    E_BAD_ARGUMENT   - invalid field pointer
 |                    E_SYSTEM_ERROR   - some severe basic error
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 _nc_Synchronize_Attributes(FIELD *field)
 {
   FORM *form;
   int res = E_OK;
-  WINDOW *formwin;
 
   T((T_CALLED("_nc_Synchronize_Attributes(%p)"), (void *)field));
 
@@ -1256,7 +1297,7 @@ _nc_Synchronize_Attributes(FIELD *field)
          werase(form->w);
          wmove(form->w, form->currow, form->curcol);
 
-         if (field->opts & O_PUBLIC)
+         if (Field_Has_Option(field, O_PUBLIC))
            {
              if (Justification_Allowed(field))
                Undo_Justification(field, form->w);
@@ -1265,14 +1306,16 @@ _nc_Synchronize_Attributes(FIELD *field)
            }
          else
            {
-             formwin = Get_Form_Window(form);
+             WINDOW *formwin = Get_Form_Window(form);
+
              copywin(form->w, formwin,
                      0, 0,
                      field->frow, field->fcol,
-                     field->rows - 1, field->cols - 1, 0);
+                     field->frow + field->rows - 1,
+                     field->fcol + field->cols - 1, 0);
              wsyncup(formwin);
              Buffer_To_Window(field, form->w);
-             field->status |= _NEWTOP;         /* fake refresh to paint all */
+             SetStatus(field, _NEWTOP);        /* fake refresh to paint all */
              _nc_Refresh_Current_Field(form);
            }
        }
@@ -1290,7 +1333,7 @@ _nc_Synchronize_Attributes(FIELD *field)
 |   Function      :  int _nc_Synchronize_Options(FIELD * field,
 |                                                Field_Options newopts)
 |
-|   Description   :  If a fields options have changed, this routine is
+|   Description   :  If a field's options have changed, this routine is
 |                    called to propagate these changes to the screen and
 |                    to really change the behavior of the field.
 |
@@ -1299,7 +1342,7 @@ _nc_Synchronize_Attributes(FIELD *field)
 |                    E_CURRENT           - field is the current one
 |                    E_SYSTEM_ERROR      - some severe basic error
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
 {
   Field_Options oldopts;
@@ -1326,34 +1369,34 @@ _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
              field->opts = oldopts;
              returnCode(E_CURRENT);
            }
-         if ((form->curpage == field->page))
+         if (form->curpage == field->page)
            {
-             if (changed_opts & O_VISIBLE)
+             if ((unsigned)changed_opts & O_VISIBLE)
                {
-                 if (newopts & O_VISIBLE)
+                 if ((unsigned)newopts & O_VISIBLE)
                    res = Display_Field(field);
                  else
                    res = Erase_Field(field);
                }
              else
                {
-                 if ((changed_opts & O_PUBLIC) &&
-                     (newopts & O_VISIBLE))
+                 if (((unsigned)changed_opts & O_PUBLIC) &&
+                     ((unsigned)newopts & O_VISIBLE))
                    res = Display_Field(field);
                }
            }
        }
     }
 
-  if (changed_opts & O_STATIC)
+  if ((unsigned)changed_opts & O_STATIC)
     {
       bool single_line_field = Single_Line_Field(field);
       int res2 = E_OK;
 
-      if (newopts & O_STATIC)
+      if ((unsigned)newopts & O_STATIC)
        {
          /* the field becomes now static */
-         field->status &= ~_MAY_GROW;
+         ClrStatus(field, _MAY_GROW);
          /* if actually we have no hidden columns, justification may
             occur again */
          if (single_line_field &&
@@ -1371,7 +1414,7 @@ _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
              (single_line_field && (field->dcols < field->maxgrow)) ||
              (!single_line_field && (field->drows < field->maxgrow)))
            {
-             field->status |= _MAY_GROW;
+             SetStatus(field, _MAY_GROW);
              /* a field with justification now changes its behavior,
                 so we must redisplay it */
              if (single_line_field &&
@@ -1389,6 +1432,57 @@ _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
   returnCode(res);
 }
 
+/*
+ * Removes the focus from the current field of the form.
+ */
+void
+_nc_Unset_Current_Field(FORM *form)
+{
+  FIELD *field = form->current;
+
+  _nc_Refresh_Current_Field(form);
+  if (Field_Has_Option(field, O_PUBLIC))
+    {
+      if (field->drows > field->rows)
+       {
+         if (form->toprow == 0)
+           ClrStatus(field, _NEWTOP);
+         else
+           SetStatus(field, _NEWTOP);
+       }
+      else
+       {
+         if (Justification_Allowed(field))
+           {
+             Window_To_Buffer(form, field);
+             werase(form->w);
+             Perform_Justification(field, form->w);
+             if (Field_Has_Option(field, O_DYNAMIC_JUSTIFY) &&
+                 (form->w->_parent == 0))
+               {
+                 copywin(form->w,
+                         Get_Form_Window(form),
+                         0,
+                         0,
+                         field->frow,
+                         field->fcol,
+                         field->frow,
+                         field->cols + field->fcol - 1,
+                         0);
+                 wsyncup(Get_Form_Window(form));
+               }
+             else
+               {
+                 wsyncup(form->w);
+               }
+           }
+       }
+    }
+  delwin(form->w);
+  form->w = (WINDOW *)0;
+  form->current = 0;
+}
+
 /*---------------------------------------------------------------------------
 |   Facility      :  libnform
 |   Function      :  int _nc_Set_Current_Field(FORM  * form,
@@ -1401,7 +1495,7 @@ _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
 |                    E_SYSTEM_ERROR    - some severe basic error
 |                    E_NOT_CONNECTED   - no fields are connected to the form
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 _nc_Set_Current_Field(FORM *form, FIELD *newfield)
 {
   FIELD *field;
@@ -1409,7 +1503,7 @@ _nc_Set_Current_Field(FORM *form, FIELD *newfield)
 
   T((T_CALLED("_nc_Set_Current_Field(%p,%p)"), (void *)form, (void *)newfield));
 
-  if (!form || !newfield || !form->current || (newfield->form != form))
+  if (!form || !newfield || (newfield->form != form))
     returnCode(E_BAD_ARGUMENT);
 
   if ((form->status & _IN_DRIVER))
@@ -1423,34 +1517,10 @@ _nc_Set_Current_Field(FORM *form, FIELD *newfield)
   if ((field != newfield) ||
       !(form->status & _POSTED))
     {
-      if ((form->w) &&
-         (field->opts & O_VISIBLE) &&
+      if (field && (form->w) &&
+         (Field_Has_Option(field, O_VISIBLE)) &&
          (field->form->curpage == field->page))
-       {
-         _nc_Refresh_Current_Field(form);
-         if (field->opts & O_PUBLIC)
-           {
-             if (field->drows > field->rows)
-               {
-                 if (form->toprow == 0)
-                   field->status &= ~_NEWTOP;
-                 else
-                   field->status |= _NEWTOP;
-               }
-             else
-               {
-                 if (Justification_Allowed(field))
-                   {
-                     Window_To_Buffer(form, field);
-                     werase(form->w);
-                     Perform_Justification(field, form->w);
-                     wsyncup(form->w);
-                   }
-               }
-           }
-         delwin(form->w);
-         form->w = (WINDOW *)0;
-       }
+       _nc_Unset_Current_Field(form);
 
       field = newfield;
 
@@ -1469,7 +1539,7 @@ _nc_Set_Current_Field(FORM *form, FIELD *newfield)
        delwin(form->w);
       form->w = new_window;
 
-      form->status &= ~_WINDOW_MODIFIED;
+      ClrStatus(form, _WINDOW_MODIFIED);
       Set_Field_Window_Attributes(field, form->w);
 
       if (Has_Invisible_Parts(field))
@@ -1998,7 +2068,7 @@ Vertical_Scrolling(int (*const fct) (FORM *), FORM *form)
     {
       res = fct(form);
       if (res == E_OK)
-       form->current->status |= _NEWTOP;
+       SetStatus(form->current, _NEWTOP);
     }
   return (res);
 }
@@ -2356,7 +2426,6 @@ Insert_String(FORM *form, int row, FIELD_CELL *txt, int len)
   int datalen = (int)(After_End_Of_Data(bp, field->dcols) - bp);
   int freelen = field->dcols - datalen;
   int requiredlen = len + 1;
-  FIELD_CELL *split;
   int result = E_REQUEST_DENIED;
 
   if (freelen >= requiredlen)
@@ -2365,7 +2434,7 @@ Insert_String(FORM *form, int row, FIELD_CELL *txt, int len)
       myINSNSTR(form->w, txt, len);
       wmove(form->w, row, len);
       myINSNSTR(form->w, &myBLANK, 1);
-      return E_OK;
+      result = E_OK;
     }
   else
     {
@@ -2381,6 +2450,8 @@ Insert_String(FORM *form, int row, FIELD_CELL *txt, int len)
 
       if (row < (field->drows - 1))
        {
+         FIELD_CELL *split;
+
          split =
            After_Last_Whitespace_Character(bp,
                                            (int)(Get_Start_Of_Data(bp
@@ -2404,8 +2475,8 @@ Insert_String(FORM *form, int row, FIELD_CELL *txt, int len)
              return E_OK;
            }
        }
-      return (result);
     }
+  return (result);
 }
 
 /*---------------------------------------------------------------------------
@@ -2430,7 +2501,7 @@ Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM *form)
   int result = E_REQUEST_DENIED;
   bool Last_Row = ((field->drows - 1) == form->currow);
 
-  if ((field->opts & O_WRAP) &&        /* wrapping wanted     */
+  if ((Field_Has_Option(field, O_WRAP)) &&     /* wrapping wanted     */
       (!Single_Line_Field(field)) &&   /* must be multi-line  */
       (There_Is_No_Room_For_A_Char_In_Line(form)) &&   /* line is full        */
       (!Last_Row || Growable(field)))  /* there are more lines */
@@ -2513,7 +2584,7 @@ Field_Editing(int (*const fct) (FORM *), FORM *form)
      editable fields.
    */
   if ((fct == FE_Delete_Previous) &&
-      (form->opts & O_BS_OVERLOAD) &&
+      ((unsigned)form->opts & O_BS_OVERLOAD) &&
       First_Position_In_Current_Field(form))
     {
       res = Inter_Field_Navigation(FN_Previous_Field, form);
@@ -2522,7 +2593,7 @@ Field_Editing(int (*const fct) (FORM *), FORM *form)
     {
       if (fct == FE_New_Line)
        {
-         if ((form->opts & O_NL_OVERLOAD) &&
+         if (((unsigned)form->opts & O_NL_OVERLOAD) &&
              First_Position_In_Current_Field(form))
            {
              res = Inter_Field_Navigation(FN_Next_Field, form);
@@ -2534,11 +2605,11 @@ Field_Editing(int (*const fct) (FORM *), FORM *form)
       else
        {
          /* From now on, everything must be editable */
-         if (form->current->opts & O_EDIT)
+         if ((unsigned)form->current->opts & O_EDIT)
            {
              res = fct(form);
              if (res == E_OK)
-               form->status |= _WINDOW_MODIFIED;
+               SetStatus(form, _WINDOW_MODIFIED);
            }
        }
     }
@@ -2571,7 +2642,7 @@ FE_New_Line(FORM *form)
       if (Last_Row &&
          (!(Growable(field) && !Single_Line_Field(field))))
        {
-         if (!(form->opts & O_NL_OVERLOAD))
+         if (!((unsigned)form->opts & O_NL_OVERLOAD))
            returnCode(E_REQUEST_DENIED);
          wmove(form->w, form->currow, form->curcol);
          wclrtoeol(form->w);
@@ -2579,7 +2650,7 @@ FE_New_Line(FORM *form)
             handled in the generic routine. The reason is,
             that FN_Next_Field may fail, but the form is
             definitively changed */
-         form->status |= _WINDOW_MODIFIED;
+         SetStatus(form, _WINDOW_MODIFIED);
          returnCode(Inter_Field_Navigation(FN_Next_Field, form));
        }
       else
@@ -2595,7 +2666,7 @@ FE_New_Line(FORM *form)
          wclrtoeol(form->w);
          form->currow++;
          form->curcol = 0;
-         form->status |= _WINDOW_MODIFIED;
+         SetStatus(form, _WINDOW_MODIFIED);
          returnCode(E_OK);
        }
     }
@@ -2605,7 +2676,7 @@ FE_New_Line(FORM *form)
       if (Last_Row &&
          !(Growable(field) && !Single_Line_Field(field)))
        {
-         if (!(form->opts & O_NL_OVERLOAD))
+         if (!((unsigned)form->opts & O_NL_OVERLOAD))
            returnCode(E_REQUEST_DENIED);
          returnCode(Inter_Field_Navigation(FN_Next_Field, form));
        }
@@ -2627,7 +2698,7 @@ FE_New_Line(FORM *form)
          wmove(form->w, form->currow, form->curcol);
          winsertln(form->w);
          myADDNSTR(form->w, bp, (int)(t - bp));
-         form->status |= _WINDOW_MODIFIED;
+         SetStatus(form, _WINDOW_MODIFIED);
          returnCode(E_OK);
        }
     }
@@ -2926,7 +2997,7 @@ static int
 EM_Overlay_Mode(FORM *form)
 {
   T((T_CALLED("EM_Overlay_Mode(%p)"), (void *)form));
-  form->status |= _OVLMODE;
+  SetStatus(form, _OVLMODE);
   returnCode(E_OK);
 }
 
@@ -2942,7 +3013,7 @@ static int
 EM_Insert_Mode(FORM *form)
 {
   T((T_CALLED("EM_Insert_Mode(%p)"), (void *)form));
-  form->status &= ~_OVLMODE;
+  ClrStatus(form, _OVLMODE);
   returnCode(E_OK);
 }
 
@@ -3111,7 +3182,7 @@ Check_Field(FORM *form, FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
 {
   if (typ)
     {
-      if (field->opts & O_NULLOK)
+      if (Field_Has_Option(field, O_NULLOK))
        {
          FIELD_CELL *bp = field->buf;
 
@@ -3159,7 +3230,7 @@ Check_Field(FORM *form, FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
 |   Return Values :  TRUE  - field is valid
 |                    FALSE - field is invalid
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(bool)
+FORM_EXPORT(bool)
 _nc_Internal_Validation(FORM *form)
 {
   FIELD *field;
@@ -3168,12 +3239,12 @@ _nc_Internal_Validation(FORM *form)
 
   Synchronize_Buffer(form);
   if ((form->status & _FCHECK_REQUIRED) ||
-      (!(field->opts & O_PASSOK)))
+      (!(Field_Has_Option(field, O_PASSOK))))
     {
       if (!Check_Field(form, field->type, field, (TypeArgument *)(field->arg)))
        return FALSE;
-      form->status &= ~_FCHECK_REQUIRED;
-      field->status |= _CHANGED;
+      ClrStatus(form, _FCHECK_REQUIRED);
+      SetStatus(field, _CHANGED);
       Synchronize_Linked_Fields(field);
     }
   return TRUE;
@@ -3218,7 +3289,7 @@ FV_Validation(FORM *form)
 |
 |   Description   :  Get the next field after the given field on the current
 |                    page. The order of fields is the one defined by the
-|                    fields array. Only visible and active fields are
+|                    field's array. Only visible and active fields are
 |                    counted.
 |
 |   Return Values :  Pointer to the next field.
@@ -3253,7 +3324,7 @@ Next_Field_On_Page(FIELD *field)
 |
 |   Return Values :  Pointer to calculated field.
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(FIELD *)
+FORM_EXPORT(FIELD *)
 _nc_First_Active_Field(FORM *form)
 {
   FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
@@ -3273,14 +3344,15 @@ _nc_First_Active_Field(FORM *form)
          do
            {
              field = (field == last_on_page) ? first : field + 1;
-             if (((*field)->opts & O_VISIBLE))
+             if (Field_Has_Option(*field, O_VISIBLE))
                break;
            }
          while (proposed != (*field));
 
          proposed = *field;
 
-         if ((proposed == *last_on_page) && !(proposed->opts & O_VISIBLE))
+         if ((proposed == *last_on_page) &&
+             !((unsigned)proposed->opts & O_VISIBLE))
            {
              /* This means, there is also no visible field on the page.
                 So we propose the first one and hope the very best...
@@ -3300,7 +3372,7 @@ _nc_First_Active_Field(FORM *form)
 |
 |   Description   :  Get the previous field before the given field on the
 |                    current page. The order of fields is the one defined by
-|                    the fields array. Only visible and active fields are
+|                    the field's array. Only visible and active fields are
 |                    counted.
 |
 |   Return Values :  Pointer to the previous field.
@@ -3434,10 +3506,10 @@ Right_Neighbor_Field(FIELD *field)
 |   Function      :  static FIELD *Upper_Neighbor_Field(FIELD * field)
 |
 |   Description   :  Because of the row-major nature of sorting the fields,
-|                    it is more difficult to define whats the upper neighbor
+|                    it is more difficult to define what the upper neighbor
 |                    field really means. We define that it must be on a
 |                    'previous' line (cyclic order!) and is the rightmost
-|                    field laying on the left side of the given field. If
+|                    field lying on the left side of the given field. If
 |                    this set is empty, we take the first field on the line.
 |
 |   Return Values :  Pointer to the upper neighbor field.
@@ -3484,7 +3556,7 @@ Upper_Neighbor_Field(FIELD *field)
 |   Function      :  static FIELD *Down_Neighbor_Field(FIELD * field)
 |
 |   Description   :  Because of the row-major nature of sorting the fields,
-|                    its more difficult to define whats the down neighbor
+|                    it is more difficult to define what the down neighbor
 |                    field really means. We define that it must be on a
 |                    'next' line (cyclic order!) and is the leftmost
 |                    field laying on the right side of the given field. If
@@ -3806,7 +3878,7 @@ FN_Down_Field(FORM *form)
 |                    E_BAD_ARGUMENT      - invalid field pointer
 |                    E_SYSTEM_ERROR      - some severe basic error
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 _nc_Set_Form_Page(FORM *form, int page, FIELD *field)
 {
   int res = E_OK;
@@ -3816,11 +3888,11 @@ _nc_Set_Form_Page(FORM *form, int page, FIELD *field)
       FIELD *last_field, *field_on_page;
 
       werase(Get_Form_Window(form));
-      form->curpage = page;
+      form->curpage = (short)page;
       last_field = field_on_page = form->field[form->page[page].smin];
       do
        {
-         if (field_on_page->opts & O_VISIBLE)
+         if ((unsigned)field_on_page->opts & O_VISIBLE)
            if ((res = Display_Field(field_on_page)) != E_OK)
              return (res);
          field_on_page = field_on_page->snext;
@@ -3885,7 +3957,7 @@ Previous_Page_Number(const FORM *form)
 |                    that the field is left and a new field is entered.
 |                    So the field must be validated and the field init/term
 |                    hooks must be called. Because also the page is changed,
-|                    the forms init/term hooks must be called also.
+|                    the form's init/term hooks must be called also.
 |
 |   Return Values :  E_OK                - success
 |                    E_INVALID_FIELD     - field is invalid
@@ -3981,6 +4053,94 @@ PN_Last_Page(FORM *form)
   Helper routines for the core form driver.
   --------------------------------------------------------------------------*/
 
+# if USE_WIDEC_SUPPORT
+/*---------------------------------------------------------------------------
+|   Facility      :  libnform
+|   Function      :  static int Data_Entry_w(FORM * form, wchar_t c)
+|
+|   Description   :  Enter the wide character c into at the current
+|                    position of the current field of the form.
+|
+|   Return Values :  E_OK              - success
+|                    E_REQUEST_DENIED  - driver could not process the request
+|                    E_SYSTEM_ERROR    -
++--------------------------------------------------------------------------*/
+static int
+Data_Entry_w(FORM *form, wchar_t c)
+{
+  FIELD *field = form->current;
+  int result = E_REQUEST_DENIED;
+
+  T((T_CALLED("Data_Entry(%p,%s)"), (void *)form, _tracechtype((chtype)c)));
+  if ((Field_Has_Option(field, O_EDIT))
+#if FIX_FORM_INACTIVE_BUG
+      && (Field_Has_Option(field, O_ACTIVE))
+#endif
+    )
+    {
+      wchar_t given[2];
+      cchar_t temp_ch;
+
+      given[0] = c;
+      given[1] = 0;
+      setcchar(&temp_ch, given, 0, 0, (void *)0);
+      if ((Field_Has_Option(field, O_BLANK)) &&
+         First_Position_In_Current_Field(form) &&
+         !(form->status & _FCHECK_REQUIRED) &&
+         !(form->status & _WINDOW_MODIFIED))
+       werase(form->w);
+
+      if (form->status & _OVLMODE)
+       {
+         wadd_wch(form->w, &temp_ch);
+       }
+      else
+       /* no _OVLMODE */
+       {
+         bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
+
+         if (!(There_Is_Room ||
+               ((Single_Line_Field(field) && Growable(field)))))
+           RETURN(E_REQUEST_DENIED);
+
+         if (!There_Is_Room && !Field_Grown(field, 1))
+           RETURN(E_SYSTEM_ERROR);
+
+         wins_wch(form->w, &temp_ch);
+       }
+
+      if ((result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form)) == E_OK)
+       {
+         bool End_Of_Field = (((field->drows - 1) == form->currow) &&
+                              ((field->dcols - 1) == form->curcol));
+
+         form->status |= _WINDOW_MODIFIED;
+         if (End_Of_Field && !Growable(field) && (Field_Has_Option(field, O_AUTOSKIP)))
+           result = Inter_Field_Navigation(FN_Next_Field, form);
+         else
+           {
+             if (End_Of_Field && Growable(field) && !Field_Grown(field, 1))
+               result = E_SYSTEM_ERROR;
+             else
+               {
+                 /*
+                  * We have just added a byte to the form field.  It may have
+                  * been part of a multibyte character.  If it was, the
+                  * addch_used field is nonzero and we should not try to move
+                  * to a new column.
+                  */
+                 if (WINDOW_EXT(form->w, addch_used) == 0)
+                   IFN_Next_Character(form);
+
+                 result = E_OK;
+               }
+           }
+       }
+    }
+  RETURN(result);
+}
+# endif
+
 /*---------------------------------------------------------------------------
 |   Facility      :  libnform
 |   Function      :  static int Data_Entry(FORM * form,int c)
@@ -3999,13 +4159,13 @@ Data_Entry(FORM *form, int c)
   int result = E_REQUEST_DENIED;
 
   T((T_CALLED("Data_Entry(%p,%s)"), (void *)form, _tracechtype((chtype)c)));
-  if ((field->opts & O_EDIT)
+  if ((Field_Has_Option(field, O_EDIT))
 #if FIX_FORM_INACTIVE_BUG
-      && (field->opts & O_ACTIVE)
+      && (Field_Has_Option(field, O_ACTIVE))
 #endif
     )
     {
-      if ((field->opts & O_BLANK) &&
+      if ((Field_Has_Option(field, O_BLANK)) &&
          First_Position_In_Current_Field(form) &&
          !(form->status & _FCHECK_REQUIRED) &&
          !(form->status & _WINDOW_MODIFIED))
@@ -4035,8 +4195,14 @@ Data_Entry(FORM *form, int c)
          bool End_Of_Field = (((field->drows - 1) == form->currow) &&
                               ((field->dcols - 1) == form->curcol));
 
-         form->status |= _WINDOW_MODIFIED;
-         if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
+         if (Field_Has_Option(field, O_EDGE_INSERT_STAY))
+           move_after_insert = !!(form->curcol
+                                  - form->begincol
+                                  - field->cols
+                                  + 1);
+
+         SetStatus(form, _WINDOW_MODIFIED);
+         if (End_Of_Field && !Growable(field) && (Field_Has_Option(field, O_AUTOSKIP)))
            result = Inter_Field_Navigation(FN_Next_Field, form);
          else
            {
@@ -4193,18 +4359,20 @@ static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
 |                    E_NOT_CONNECTED   - no fields are connected to the form
 |                    E_UNKNOWN_COMMAND - command not known
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 form_driver(FORM *form, int c)
 {
-  const Binding_Info *BI = (Binding_Info *) 0;
+  const Binding_Info *BI = (Binding_Info *)0;
   int res = E_UNKNOWN_COMMAND;
 
+  move_after_insert = TRUE;
+
   T((T_CALLED("form_driver(%p,%d)"), (void *)form, c));
 
   if (!form)
     RETURN(E_BAD_ARGUMENT);
 
-  if (!(form->field))
+  if (!(form->field) || !(form->current))
     RETURN(E_NOT_CONNECTED);
 
   assert(form->page);
@@ -4228,7 +4396,10 @@ form_driver(FORM *form, int c)
 
   if ((c >= MIN_FORM_COMMAND && c <= MAX_FORM_COMMAND) &&
       ((bindings[c - MIN_FORM_COMMAND].keycode & Key_Mask) == c))
-    BI = &(bindings[c - MIN_FORM_COMMAND]);
+    {
+      TR(TRACE_CALLS, ("form_request %s", form_request_name(c)));
+      BI = &(bindings[c - MIN_FORM_COMMAND]);
+    }
 
   if (BI)
     {
@@ -4246,7 +4417,7 @@ form_driver(FORM *form, int c)
        NULL                    /* Choice Request is generic           */
       };
       size_t nMethods = (sizeof(Generic_Methods) / sizeof(Generic_Methods[0]));
-      size_t method = (BI->keycode >> ID_Shft) & 0xffff;       /* see ID_Mask */
+      size_t method = (size_t)((BI->keycode >> ID_Shft) & 0xffff);     /* see ID_Mask */
 
       if ((method >= nMethods) || !(BI->cmd))
        res = E_SYSTEM_ERROR;
@@ -4255,9 +4426,13 @@ form_driver(FORM *form, int c)
          Generic_Method fct = Generic_Methods[method];
 
          if (fct)
-           res = fct(BI->cmd, form);
+           {
+             res = fct(BI->cmd, form);
+           }
          else
-           res = (BI->cmd) (form);
+           {
+             res = (BI->cmd) (form);
+           }
        }
     }
 #ifdef NCURSES_MOUSE_VERSION
@@ -4304,14 +4479,13 @@ form_driver(FORM *form, int c)
                }
              else if (wenclose(sub, event.y, event.x))
                {               /* Inside the area we try to find the hit item */
-                 int i;
-
                  ry = event.y;
                  rx = event.x;
                  if (wmouse_trafo(sub, &ry, &rx, FALSE))
                    {
                      int min_field = form->page[form->curpage].pmin;
                      int max_field = form->page[form->curpage].pmax;
+                     int i;
 
                      for (i = min_field; i <= max_field; ++i)
                        {
@@ -4360,6 +4534,194 @@ form_driver(FORM *form, int c)
   RETURN(res);
 }
 
+# if USE_WIDEC_SUPPORT
+/*---------------------------------------------------------------------------
+|   Facility      :  libnform
+|   Function      :  int form_driver_w(FORM * form,int type,wchar_t  c)
+|
+|   Description   :  This is the workhorse of the forms system.
+|
+|                    Input is either a key code (request) or a wide char
+|                    returned by e.g. get_wch (). The type must be passed
+|                    as well,so that we are able to determine whether the char
+|                    is a multibyte char or a request.
+
+|                    If it is a request, the form driver executes
+|                    the request and returns the result. If it is data
+|                    (printable character), it enters the data into the
+|                    current position in the current field. If it is not
+|                    recognized, the form driver assumes it is an application
+|                    defined command and returns E_UNKNOWN_COMMAND.
+|                    Application defined command should be defined relative
+|                    to MAX_FORM_COMMAND, the maximum value of a request.
+|
+|   Return Values :  E_OK              - success
+|                    E_SYSTEM_ERROR    - system error
+|                    E_BAD_ARGUMENT    - an argument is incorrect
+|                    E_NOT_POSTED      - form is not posted
+|                    E_INVALID_FIELD   - field contents are invalid
+|                    E_BAD_STATE       - called from inside a hook routine
+|                    E_REQUEST_DENIED  - request failed
+|                    E_NOT_CONNECTED   - no fields are connected to the form
+|                    E_UNKNOWN_COMMAND - command not known
++--------------------------------------------------------------------------*/
+FORM_EXPORT(int)
+form_driver_w(FORM *form, int type, wchar_t c)
+{
+  const Binding_Info *BI = (Binding_Info *)0;
+  int res = E_UNKNOWN_COMMAND;
+
+  T((T_CALLED("form_driver(%p,%d)"), (void *)form, (int)c));
+
+  if (!form)
+    RETURN(E_BAD_ARGUMENT);
+
+  if (!(form->field))
+    RETURN(E_NOT_CONNECTED);
+
+  assert(form->page);
+
+  if (c == (wchar_t)FIRST_ACTIVE_MAGIC)
+    {
+      form->current = _nc_First_Active_Field(form);
+      RETURN(E_OK);
+    }
+
+  assert(form->current &&
+        form->current->buf &&
+        (form->current->form == form)
+    );
+
+  if (form->status & _IN_DRIVER)
+    RETURN(E_BAD_STATE);
+
+  if (!(form->status & _POSTED))
+    RETURN(E_NOT_POSTED);
+
+  /* check if this is a keycode or a (wide) char */
+  if (type == KEY_CODE_YES)
+    {
+      if ((c >= MIN_FORM_COMMAND && c <= MAX_FORM_COMMAND) &&
+         ((bindings[c - MIN_FORM_COMMAND].keycode & Key_Mask) == c))
+       BI = &(bindings[c - MIN_FORM_COMMAND]);
+    }
+
+  if (BI)
+    {
+      typedef int (*Generic_Method) (int (*const) (FORM *), FORM *);
+      static const Generic_Method Generic_Methods[] =
+      {
+       Page_Navigation,        /* overloaded to call field&form hooks */
+       Inter_Field_Navigation, /* overloaded to call field hooks      */
+       NULL,                   /* Intra-Field is generic              */
+       Vertical_Scrolling,     /* Overloaded to check multi-line      */
+       Horizontal_Scrolling,   /* Overloaded to check single-line     */
+       Field_Editing,          /* Overloaded to mark modification     */
+       NULL,                   /* Edit Mode is generic                */
+       NULL,                   /* Field Validation is generic         */
+       NULL                    /* Choice Request is generic           */
+      };
+      size_t nMethods = (sizeof(Generic_Methods) / sizeof(Generic_Methods[0]));
+      size_t method = (size_t)(BI->keycode >> ID_Shft) & 0xffff;       /* see ID_Mask */
+
+      if ((method >= nMethods) || !(BI->cmd))
+       res = E_SYSTEM_ERROR;
+      else
+       {
+         Generic_Method fct = Generic_Methods[method];
+
+         if (fct)
+           res = fct(BI->cmd, form);
+         else
+           res = (BI->cmd) (form);
+       }
+    }
+#ifdef NCURSES_MOUSE_VERSION
+  else if (KEY_MOUSE == c)
+    {
+      MEVENT event;
+      WINDOW *win = form->win ? form->win : StdScreen(Get_Form_Screen(form));
+      WINDOW *sub = form->sub ? form->sub : win;
+
+      getmouse(&event);
+      if ((event.bstate & (BUTTON1_CLICKED |
+                          BUTTON1_DOUBLE_CLICKED |
+                          BUTTON1_TRIPLE_CLICKED))
+         && wenclose(win, event.y, event.x))
+       {                       /* we react only if the click was in the userwin, that means
+                                  * inside the form display area or at the decoration window.
+                                */
+         int ry = event.y, rx = event.x;       /* screen coordinates */
+
+         res = E_REQUEST_DENIED;
+         if (mouse_trafo(&ry, &rx, FALSE))
+           {                   /* rx, ry are now "curses" coordinates */
+             if (ry < sub->_begy)
+               {               /* we clicked above the display region; this is
+                                  * interpreted as "scroll up" request
+                                */
+                 if (event.bstate & BUTTON1_CLICKED)
+                   res = form_driver(form, REQ_PREV_FIELD);
+                 else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
+                   res = form_driver(form, REQ_PREV_PAGE);
+                 else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
+                   res = form_driver(form, REQ_FIRST_FIELD);
+               }
+             else if (ry > sub->_begy + sub->_maxy)
+               {               /* we clicked below the display region; this is
+                                  * interpreted as "scroll down" request
+                                */
+                 if (event.bstate & BUTTON1_CLICKED)
+                   res = form_driver(form, REQ_NEXT_FIELD);
+                 else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
+                   res = form_driver(form, REQ_NEXT_PAGE);
+                 else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
+                   res = form_driver(form, REQ_LAST_FIELD);
+               }
+             else if (wenclose(sub, event.y, event.x))
+               {               /* Inside the area we try to find the hit item */
+                 ry = event.y;
+                 rx = event.x;
+                 if (wmouse_trafo(sub, &ry, &rx, FALSE))
+                   {
+                     int min_field = form->page[form->curpage].pmin;
+                     int max_field = form->page[form->curpage].pmax;
+                     int i;
+
+                     for (i = min_field; i <= max_field; ++i)
+                       {
+                         FIELD *field = form->field[i];
+
+                         if (Field_Is_Selectable(field)
+                             && Field_encloses(field, ry, rx) == E_OK)
+                           {
+                             res = _nc_Set_Current_Field(form, field);
+                             if (res == E_OK)
+                               res = _nc_Position_Form_Cursor(form);
+                             if (res == E_OK
+                                 && (event.bstate & BUTTON1_DOUBLE_CLICKED))
+                               res = E_UNKNOWN_COMMAND;
+                             break;
+                           }
+                       }
+                   }
+               }
+           }
+       }
+      else
+       res = E_REQUEST_DENIED;
+    }
+#endif /* NCURSES_MOUSE_VERSION */
+  else if (type == OK)
+    {
+      res = Data_Entry_w(form, c);
+    }
+
+  _nc_Refresh_Current_Field(form);
+  RETURN(res);
+}
+# endif        /* USE_WIDEC_SUPPORT */
+
 /*----------------------------------------------------------------------------
   Field-Buffer manipulation routines.
   The effects of setting a buffer are tightly coupled to the core of the form
@@ -4377,20 +4739,20 @@ form_driver(FORM *form, int c)
 |                    For dynamic fields this may grow the fieldbuffers if
 |                    the length of the value exceeds the current buffer
 |                    length. For buffer 0 only printable values are allowed.
-|                    For static fields, the value needs not to be zero ter-
-|                    minated. It is copied up to the length of the buffer.
+|                    For static fields, the value must not be zero terminated.
+|                    It is copied up to the length of the buffer.
 |
 |   Return Values :  E_OK            - success
 |                    E_BAD_ARGUMENT  - invalid argument
 |                    E_SYSTEM_ERROR  - system error
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 set_field_buffer(FIELD *field, int buffer, const char *value)
 {
   FIELD_CELL *p;
   int res = E_OK;
-  unsigned int i;
-  unsigned int len;
+  int i;
+  int len;
 
 #if USE_WIDEC_SUPPORT
   FIELD_CELL *widevalue = 0;
@@ -4408,7 +4770,7 @@ set_field_buffer(FIELD *field, int buffer, const char *value)
       /* for a growable field we must assume zero terminated strings, because
          somehow we have to detect the length of what should be copied.
        */
-      unsigned int vlen = strlen(value);
+      int vlen = (int)strlen(value);
 
       if (vlen > len)
        {
@@ -4417,7 +4779,9 @@ set_field_buffer(FIELD *field, int buffer, const char *value)
                                                     * field->cols))))
            RETURN(E_SYSTEM_ERROR);
 
+#if !USE_WIDEC_SUPPORT
          len = vlen;
+#endif
        }
     }
 
@@ -4438,7 +4802,7 @@ set_field_buffer(FIELD *field, int buffer, const char *value)
     }
   len = Buffer_Length(field);
   wclear(field->working);
-  mvwaddstr(field->working, 0, 0, value);
+  (void)mvwaddstr(field->working, 0, 0, value);
 
   if ((widevalue = typeCalloc(FIELD_CELL, len + 1)) == 0)
     {
@@ -4446,11 +4810,11 @@ set_field_buffer(FIELD *field, int buffer, const char *value)
     }
   else
     {
-      for (i = 0; i < (unsigned)field->drows; ++i)
+      for (i = 0; i < field->drows; ++i)
        {
-         mvwin_wchnstr(field->working, 0, i * field->dcols,
-                       widevalue + (i * field->dcols),
-                       field->dcols);
+         (void)mvwin_wchnstr(field->working, 0, (int)i * field->dcols,
+                             widevalue + ((int)i * field->dcols),
+                             field->dcols);
        }
       for (i = 0; i < len; ++i)
        {
@@ -4499,7 +4863,7 @@ set_field_buffer(FIELD *field, int buffer, const char *value)
 |
 |   Return Values :  Pointer to buffer or NULL if arguments were invalid.
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(char *)
+FORM_EXPORT(char *)
 field_buffer(const FIELD *field, int buffer)
 {
   char *result = 0;
@@ -4510,7 +4874,7 @@ field_buffer(const FIELD *field, int buffer)
     {
 #if USE_WIDEC_SUPPORT
       FIELD_CELL *data = Address_Of_Nth_Buffer(field, buffer);
-      unsigned need = 0;
+      size_t need = 0;
       int size = Buffer_Length(field);
       int n;
 
@@ -4524,7 +4888,7 @@ field_buffer(const FIELD *field, int buffer)
 
              init_mb(state);
              next = _nc_wcrtomb(0, data[n].chars[0], &state);
-             if (!isEILSEQ(next))
+             if (next > 0)
                need += next;
            }
        }
@@ -4567,7 +4931,7 @@ field_buffer(const FIELD *field, int buffer)
 | Convert a multibyte string to a wide-character string.  The result must be
 | freed by the caller.
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(wchar_t *)
+FORM_EXPORT(wchar_t *)
 _nc_Widen_String(char *source, int *lengthp)
 {
   wchar_t *result = 0;
@@ -4611,14 +4975,14 @@ _nc_Widen_String(char *source, int *lengthp)
                {
                  result[need] = wch;
                }
-             passed += status;
+             passed += (size_t)status;
              ++need;
            }
          else
            {
              if (pass)
                {
-                 result[need] = source[passed];
+                 result[need] = (wchar_t)source[passed];
                }
              ++need;
              ++passed;
@@ -4631,7 +4995,7 @@ _nc_Widen_String(char *source, int *lengthp)
            break;
          result = typeCalloc(wchar_t, need);
 
-         *lengthp = need;
+         *lengthp = (int)need;
          if (result == 0)
            break;
        }