libncurses: Import https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.5.tar.gz changes

Change-Id: I3433d30ca01359fd2e3623ede96b531f0b39cbfa
Signed-off-by: micky387 <mickaelsaibi@free.fr>
diff --git a/form/frm_driver.c b/form/frm_driver.c
index eebde42..75656d6 100644
--- a/form/frm_driver.c
+++ b/form/frm_driver.c
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 1998-2013,2014 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.115 2014/09/25 21:55:24 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 @@
 #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 @@
 /* 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)
@@ -186,7 +187,7 @@
 /* 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)((chtype)((field)->pad) | (field)->back)), \
    (void) wattrset((win), (int)(field)->fore) )
@@ -216,10 +217,10 @@
 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)
 	{
@@ -239,15 +240,36 @@
   Wide-character special functions
   --------------------------------------------------------------------------*/
 #if USE_WIDEC_SUPPORT
-/* like winsnstr */
+/* add like waddnstr, but using cchar_t* rather than char*
+ */
 static int
-wins_wchnstr(WINDOW *w, cchar_t *s, int n)
+wide_waddnstr(WINDOW *w, const cchar_t *s, int n)
 {
-  int code = ERR;
-  int y, x;
+  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
+wide_winsnstr(WINDOW *w, const cchar_t *s, int n)
+{
+  int code = ERR;
+
+  while (n-- > 0)
+    {
+      int y, x;
+
       getyx(w, y, x);
       if ((code = wins_wch(w, s++)) != OK)
 	break;
@@ -257,11 +279,13 @@
   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;
 
@@ -488,7 +512,6 @@
 {
   int width, height;
   int y, x;
-  int len;
   int row;
   FIELD_CELL *pBuffer;
 
@@ -502,6 +525,8 @@
        row < height;
        row++, pBuffer += width)
     {
+      int len;
+
       if ((len = (int)(After_End_Of_Data(pBuffer, width) - pBuffer)) > 0)
 	{
 	  wmove(win, row, 0);
@@ -525,7 +550,7 @@
 |
 |   Return Values :  -
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(void)
+FORM_EXPORT(void)
 _nc_get_fieldbuffer(FORM *form, FIELD *field, FIELD_CELL *buf)
 {
   int pad;
@@ -683,8 +708,6 @@
 	   * realloc().
 	   */
 	  int i, j;
-	  FIELD_CELL *old_bp;
-	  FIELD_CELL *new_bp;
 
 	  result = TRUE;	/* allow sharing of recovery on failure */
 
@@ -692,8 +715,9 @@
 	  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)
@@ -803,7 +827,7 @@
 |                    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;
@@ -837,18 +861,20 @@
 |   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));
 
@@ -861,102 +887,106 @@
   field = form->current;
   formwin = Get_Form_Window(form);
 
-  if (Field_Has_Option(field, 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
-		{
-		  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);
-	    }
+	  /* horizontal scrolling */
+	  if (form->curcol < form->begincol)
+	    form->begincol = form->curcol;
 	  else
 	    {
-	      /* A multi-line, i.e. vertical scrolling field */
-	      int row_after_bottom, first_modified_row, first_unmodified_row;
-
-	      if (field->drows > field->rows)
-		{
-		  row_after_bottom = form->toprow + field->rows;
-		  if (form->currow < form->toprow)
-		    {
-		      form->toprow = form->currow;
-		      SetStatus(field, _NEWTOP);
-		    }
-		  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++;
-			}
-		    }
-		}
-	      else
-		{
-		  first_modified_row = form->toprow;
-		  first_unmodified_row = first_modified_row + field->rows;
-		}
-	      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);
+	      if (form->curcol >= (form->begincol + field->cols))
+		form->begincol = form->curcol - field->cols
+		  + (move_after_insert ? 1 : 0);
 	    }
-	  wsyncup(formwin);
+	  if (is_public)
+	    copywin(form->w,
+		    formwin,
+		    0,
+		    form->begincol,
+		    field->frow,
+		    field->fcol,
+		    field->frow,
+		    field->cols + field->fcol - 1,
+		    0);
 	}
       else
 	{
-	  /* if the field-window is simply a derived window, i.e. contains no
-	   * invisible parts, the whole thing is trivial
-	   */
-	  wsyncup(form->w);
+	  /* A multi-line, i.e. vertical scrolling field */
+	  int first_modified_row, first_unmodified_row;
+
+	  if (field->drows > field->rows)
+	    {
+	      int row_after_bottom = form->toprow + field->rows;
+
+	      if (form->currow < form->toprow)
+		{
+		  form->toprow = form->currow;
+		  SetStatus(field, _NEWTOP);
+		}
+	      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++;
+		    }
+		}
+	    }
+	  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));
@@ -977,13 +1007,16 @@
 {
   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)
     {
+      int col = 0;
+
       assert(win && (field->drows == 1));
 
       if (field->cols - len >= 0)
@@ -1021,9 +1054,14 @@
 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)
@@ -1032,6 +1070,7 @@
       wmove(win, 0, 0);
       myADDNSTR(win, bp, len);
     }
+  wmove(win, y, x);
 }
 
 /*---------------------------------------------------------------------------
@@ -1204,7 +1243,6 @@
 {
   FIELD *linked_field;
   int res = E_OK;
-  int syncres;
 
   if (!field)
     return (E_BAD_ARGUMENT);
@@ -1216,6 +1254,8 @@
        (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;
@@ -1227,7 +1267,7 @@
 |   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.
 |
@@ -1235,12 +1275,11 @@
 |                    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));
 
@@ -1267,11 +1306,13 @@
 	    }
 	  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);
 	      SetStatus(field, _NEWTOP);	/* fake refresh to paint all */
@@ -1292,7 +1333,7 @@
 |   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.
 |
@@ -1301,7 +1342,7 @@
 |                    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;
@@ -1391,6 +1432,57 @@
   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,
@@ -1403,7 +1495,7 @@
 |                    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;
@@ -1411,7 +1503,7 @@
 
   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))
@@ -1425,51 +1517,10 @@
   if ((field != newfield) ||
       !(form->status & _POSTED))
     {
-      if ((form->w) &&
+      if (field && (form->w) &&
 	  (Field_Has_Option(field, O_VISIBLE)) &&
 	  (field->form->curpage == field->page))
-	{
-	  _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;
-	}
+	_nc_Unset_Current_Field(form);
 
       field = newfield;
 
@@ -2375,7 +2426,6 @@
   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)
@@ -2384,7 +2434,7 @@
       myINSNSTR(form->w, txt, len);
       wmove(form->w, row, len);
       myINSNSTR(form->w, &myBLANK, 1);
-      return E_OK;
+      result = E_OK;
     }
   else
     {
@@ -2400,6 +2450,8 @@
 
       if (row < (field->drows - 1))
 	{
+	  FIELD_CELL *split;
+
 	  split =
 	    After_Last_Whitespace_Character(bp,
 					    (int)(Get_Start_Of_Data(bp
@@ -2423,8 +2475,8 @@
 	      return E_OK;
 	    }
 	}
-      return (result);
     }
+  return (result);
 }
 
 /*---------------------------------------------------------------------------
@@ -3178,7 +3230,7 @@
 |   Return Values :  TRUE  - field is valid
 |                    FALSE - field is invalid
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(bool)
+FORM_EXPORT(bool)
 _nc_Internal_Validation(FORM *form)
 {
   FIELD *field;
@@ -3237,7 +3289,7 @@
 |
 |   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.
@@ -3272,7 +3324,7 @@
 |
 |   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];
@@ -3320,7 +3372,7 @@
 |
 |   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.
@@ -3454,10 +3506,10 @@
 |   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.
@@ -3504,7 +3556,7 @@
 |   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
@@ -3826,7 +3878,7 @@
 |                    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;
@@ -3905,7 +3957,7 @@
 |                    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
@@ -4030,7 +4082,7 @@
       cchar_t temp_ch;
 
       given[0] = c;
-      given[1] = 1;
+      given[1] = 0;
       setcchar(&temp_ch, given, 0, 0, (void *)0);
       if ((Field_Has_Option(field, O_BLANK)) &&
 	  First_Position_In_Current_Field(form) &&
@@ -4143,6 +4195,12 @@
 	  bool End_Of_Field = (((field->drows - 1) == form->currow) &&
 			       ((field->dcols - 1) == form->curcol));
 
+	  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);
@@ -4301,18 +4359,20 @@
 |                    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);
@@ -4357,7 +4417,7 @@
 	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 */
+      size_t method = (size_t)((BI->keycode >> ID_Shft) & 0xffff);	/* see ID_Mask */
 
       if ((method >= nMethods) || !(BI->cmd))
 	res = E_SYSTEM_ERROR;
@@ -4419,14 +4479,13 @@
 		}
 	      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)
 			{
@@ -4506,10 +4565,10 @@
 |                    E_NOT_CONNECTED   - no fields are connected to the form
 |                    E_UNKNOWN_COMMAND - command not known
 +--------------------------------------------------------------------------*/
-NCURSES_EXPORT(int)
+FORM_EXPORT(int)
 form_driver_w(FORM *form, int type, wchar_t c)
 {
-  const Binding_Info *BI = (Binding_Info *) 0;
+  const Binding_Info *BI = (Binding_Info *)0;
   int res = E_UNKNOWN_COMMAND;
 
   T((T_CALLED("form_driver(%p,%d)"), (void *)form, (int)c));
@@ -4563,7 +4622,7 @@
 	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 */
+      size_t method = (size_t)(BI->keycode >> ID_Shft) & 0xffff;	/* see ID_Mask */
 
       if ((method >= nMethods) || !(BI->cmd))
 	res = E_SYSTEM_ERROR;
@@ -4621,14 +4680,13 @@
 		}
 	      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)
 			{
@@ -4681,14 +4739,14 @@
 |                    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;
@@ -4805,7 +4863,7 @@
 |
 |   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;
@@ -4873,7 +4931,7 @@
 | 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;
@@ -4917,7 +4975,7 @@
 		{
 		  result[need] = wch;
 		}
-	      passed += (size_t) status;
+	      passed += (size_t)status;
 	      ++need;
 	    }
 	  else