150276Speter/****************************************************************************
2176187Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
30166124Srafan *   Author:  Juergen Pfeifer, 1995,1997                                    *
3150276Speter ****************************************************************************/
32166124Srafan
3350276Speter#include "form.priv.h"
3450276Speter
35184989SrafanMODULE_ID("$Id: frm_driver.c,v 1.88 2008/10/18 16:25:00 tom Exp $")
3650276Speter
3750276Speter/*----------------------------------------------------------------------------
3850276Speter  This is the core module of the form library. It contains the majority
39166124Srafan  of the driver routines as well as the form_driver function.
4050276Speter
4150276Speter  Essentially this module is nearly the whole library. This is because
4250276Speter  all the functions in this module depends on some others in the module,
4350276Speter  so it makes no sense to split them into separate files because they
4450276Speter  will always be linked together. The only acceptable concern is turnaround
45166124Srafan  time for this module, but now we have all Pentiums or RISCs, so what!
4650276Speter
4750276Speter  The driver routines are grouped into nine generic categories:
4850276Speter
4950276Speter   a)   Page Navigation            ( all functions prefixed by PN_ )
5050276Speter        The current page of the form is left and some new page is
5150276Speter        entered.
5250276Speter   b)   Inter-Field Navigation     ( all functions prefixed by FN_ )
5350276Speter        The current field of the form is left and some new field is
5450276Speter        entered.
5550276Speter   c)   Intra-Field Navigation     ( all functions prefixed by IFN_ )
56166124Srafan        The current position in the current field is changed.
5750276Speter   d)   Vertical Scrolling         ( all functions prefixed by VSC_ )
58166124Srafan        Essentially this is a specialization of Intra-Field navigation.
5950276Speter        It has to check for a multi-line field.
6050276Speter   e)   Horizontal Scrolling       ( all functions prefixed by HSC_ )
61166124Srafan        Essentially this is a specialization of Intra-Field navigation.
6250276Speter        It has to check for a single-line field.
6350276Speter   f)   Field Editing              ( all functions prefixed by FE_ )
6450276Speter        The content of the current field is changed
6550276Speter   g)   Edit Mode requests         ( all functions prefixed by EM_ )
6650276Speter        Switching between insert and overlay mode
6750276Speter   h)   Field-Validation requests  ( all functions prefixed by FV_ )
6850276Speter        Perform verifications of the field.
6950276Speter   i)   Choice requests            ( all functions prefixed by CR_ )
7050276Speter        Requests to enumerate possible field values
7150276Speter  --------------------------------------------------------------------------*/
7250276Speter
7350276Speter/*----------------------------------------------------------------------------
7450276Speter  Some remarks on the placements of assert() macros :
7550276Speter  I use them only on "strategic" places, i.e. top level entries where
7650276Speter  I want to make sure that things are set correctly. Throughout subordinate
7750276Speter  routines I omit them mostly.
7850276Speter  --------------------------------------------------------------------------*/
7950276Speter
8050276Speter/*
8150276SpeterSome options that may effect compatibility in behavior to SVr4 forms,
82166124Srafanbut they are here to allow a more intuitive and user friendly behavior of
8350276Speterour form implementation. This doesn't affect the API, so we feel it is
8450276Speteruncritical.
8550276Speter
86166124SrafanThe initial implementation tries to stay very close with the behavior
8750276Speterof the original SVr4 implementation, although in some areas it is quite
8850276Speterclear that this isn't the most appropriate way. As far as possible this
8950276Spetersources will allow you to build a forms lib that behaves quite similar
90166124Srafanto SVr4, but now and in the future we will give you better options.
9150276SpeterPerhaps at some time we will make this configurable at runtime.
9250276Speter*/
9350276Speter
94166124Srafan/* Implement a more user-friendly previous/next word behavior */
9550276Speter#define FRIENDLY_PREV_NEXT_WORD (1)
96166124Srafan/* Fix the wrong behavior for forms with all fields inactive */
9750276Speter#define FIX_FORM_INACTIVE_BUG (1)
9850276Speter/* Allow dynamic field growth also when navigating past the end */
9950276Speter#define GROW_IF_NAVIGATE (1)
10050276Speter
101166124Srafan#if USE_WIDEC_SUPPORT
102166124Srafan#define myADDNSTR(w, s, n) wadd_wchnstr(w, s, n)
103166124Srafan#define myINSNSTR(w, s, n) wins_wchnstr(w, s, n)
104166124Srafan#define myINNSTR(w, s, n)  fix_wchnstr(w, s, n)
105166124Srafan#define myWCWIDTH(w, y, x) cell_width(w, y, x)
106166124Srafan#else
107166124Srafan#define myADDNSTR(w, s, n) waddnstr(w, s, n)
108166124Srafan#define myINSNSTR(w, s, n) winsnstr(w, s, n)
109166124Srafan#define myINNSTR(w, s, n)  winnstr(w, s, n)
110166124Srafan#define myWCWIDTH(w, y, x) 1
111166124Srafan#endif
112166124Srafan
11350276Speter/*----------------------------------------------------------------------------
11450276Speter  Forward references to some internally used static functions
11550276Speter  --------------------------------------------------------------------------*/
116166124Srafanstatic int Inter_Field_Navigation(int (*const fct) (FORM *), FORM *form);
117166124Srafanstatic int FN_Next_Field(FORM *form);
118166124Srafanstatic int FN_Previous_Field(FORM *form);
11950276Speterstatic int FE_New_Line(FORM *);
12050276Speterstatic int FE_Delete_Previous(FORM *);
121166124Srafan
12250276Speter/*----------------------------------------------------------------------------
12350276Speter  Macro Definitions.
12450276Speter
12550276Speter  Some Remarks on that: I use the convention to use UPPERCASE for constants
12650276Speter  defined by Macros. If I provide a macro as a kind of inline routine to
12750276Speter  provide some logic, I use my Upper_Lower case style.
12850276Speter  --------------------------------------------------------------------------*/
12950276Speter
13050276Speter/* Calculate the position of a single row in a field buffer */
13150276Speter#define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
13250276Speter
13350276Speter/* Calculate start address for the fields buffer# N */
13450276Speter#define Address_Of_Nth_Buffer(field,N) \
13550276Speter  ((field)->buf + (N)*(1+Buffer_Length(field)))
13650276Speter
13750276Speter/* Calculate the start address of the row in the fields specified buffer# N */
13850276Speter#define Address_Of_Row_In_Nth_Buffer(field,N,row) \
13950276Speter  (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
14050276Speter
14150276Speter/* Calculate the start address of the row in the fields primary buffer */
14250276Speter#define Address_Of_Row_In_Buffer(field,row) \
14350276Speter  Address_Of_Row_In_Nth_Buffer(field,0,row)
14450276Speter
14550276Speter/* Calculate the start address of the row in the forms current field
14650276Speter   buffer# N */
14750276Speter#define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
14850276Speter   Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
14950276Speter
15050276Speter/* Calculate the start address of the row in the forms current field
15150276Speter   primary buffer */
15250276Speter#define Address_Of_Current_Row_In_Buffer(form) \
15350276Speter   Address_Of_Current_Row_In_Nth_Buffer(form,0)
15450276Speter
15550276Speter/* Calculate the address of the cursor in the forms current field
15650276Speter   primary buffer */
15750276Speter#define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
15850276Speter   (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
15950276Speter
16050276Speter/* Calculate the address of the cursor in the forms current field
16150276Speter   buffer# N */
16250276Speter#define Address_Of_Current_Position_In_Buffer(form) \
16350276Speter  Address_Of_Current_Position_In_Nth_Buffer(form,0)
16450276Speter
165166124Srafan/* Logic to decide whether or not a field is actually a field with
16650276Speter   vertical or horizontal scrolling */
16750276Speter#define Is_Scroll_Field(field)          \
16850276Speter   (((field)->drows > (field)->rows) || \
16950276Speter    ((field)->dcols > (field)->cols))
17050276Speter
17150276Speter/* Logic to decide whether or not a field needs to have an individual window
17250276Speter   instead of a derived window because it contains invisible parts.
17350276Speter   This is true for non-public fields and for scrollable fields. */
17450276Speter#define Has_Invisible_Parts(field)     \
17550276Speter  (!((field)->opts & O_PUBLIC)      || \
17650276Speter   Is_Scroll_Field(field))
17750276Speter
17850276Speter/* Logic to decide whether or not a field needs justification */
17950276Speter#define Justification_Allowed(field)        \
18050276Speter   (((field)->just != NO_JUSTIFICATION)  && \
18150276Speter    (Single_Line_Field(field))           && \
18250276Speter    (((field)->dcols == (field)->cols)   && \
18350276Speter    ((field)->opts & O_STATIC))             )
18450276Speter
18550276Speter/* Logic to determine whether or not a dynamic field may still grow */
18650276Speter#define Growable(field) ((field)->status & _MAY_GROW)
18750276Speter
18850276Speter/* Macro to set the attributes for a fields window */
18950276Speter#define Set_Field_Window_Attributes(field,win) \
19050276Speter(  wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
19150276Speter   wattrset((win),(field)->fore) )
19250276Speter
19350276Speter/* Logic to decide whether or not a field really appears on the form */
19450276Speter#define Field_Really_Appears(field)         \
19550276Speter  ((field->form)                          &&\
19650276Speter   (field->form->status & _POSTED)        &&\
19750276Speter   (field->opts & O_VISIBLE)              &&\
19850276Speter   (field->page == field->form->curpage))
19950276Speter
20050276Speter/* Logic to determine whether or not we are on the first position in the
20150276Speter   current field */
20250276Speter#define First_Position_In_Current_Field(form) \
20350276Speter  (((form)->currow==0) && ((form)->curcol==0))
20450276Speter
20550276Speter#define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
20650276Speter#define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
207166124Srafan
208166124Srafan/*----------------------------------------------------------------------------
209166124Srafan  Useful constants
210166124Srafan  --------------------------------------------------------------------------*/
211166124Srafanstatic FIELD_CELL myBLANK = BLANK;
212166124Srafanstatic FIELD_CELL myZEROS;
213166124Srafan
214166124Srafan#ifdef TRACE
215166124Srafanstatic void
216166124Srafancheck_pos(FORM *form, int lineno)
217166124Srafan{
218166124Srafan  int y, x;
219166124Srafan
220166124Srafan  if (form && form->w)
221166124Srafan    {
222166124Srafan      getyx(form->w, y, x);
223166124Srafan      if (y != form->currow || x != form->curcol)
224166124Srafan	{
225166124Srafan	  T(("CHECKPOS %s@%d have position %d,%d vs want %d,%d",
226166124Srafan	     __FILE__, lineno,
227166124Srafan	     y, x,
228166124Srafan	     form->currow, form->curcol));
229166124Srafan	}
230166124Srafan    }
231166124Srafan}
232166124Srafan#define CHECKPOS(form) check_pos(form, __LINE__)
233166124Srafan#else
234166124Srafan#define CHECKPOS(form)		/* nothing */
235166124Srafan#endif
236166124Srafan
237166124Srafan/*----------------------------------------------------------------------------
238166124Srafan  Wide-character special functions
239166124Srafan  --------------------------------------------------------------------------*/
240166124Srafan#if USE_WIDEC_SUPPORT
241166124Srafan/* like winsnstr */
242166124Srafanstatic int
243166124Srafanwins_wchnstr(WINDOW *w, cchar_t *s, int n)
244166124Srafan{
245166124Srafan  int code = ERR;
246166124Srafan  int y, x;
247166124Srafan
248166124Srafan  while (n-- > 0)
249166124Srafan    {
250166124Srafan      getyx(w, y, x);
251166124Srafan      if ((code = wins_wch(w, s++)) != OK)
252166124Srafan	break;
253166124Srafan      if ((code = wmove(w, y, x + 1)) != OK)
254166124Srafan	break;
255166124Srafan    }
256166124Srafan  return code;
257166124Srafan}
258166124Srafan
259166124Srafan/* win_wchnstr is inconsistent with winnstr, since it returns OK rather than
260166124Srafan * the number of items transferred.
261166124Srafan */
262166124Srafanstatic int
263166124Srafanfix_wchnstr(WINDOW *w, cchar_t *s, int n)
264166124Srafan{
265174993Srafan  int x;
266174993Srafan
267166124Srafan  win_wchnstr(w, s, n);
268174993Srafan  /*
269174993Srafan   * This function is used to extract the text only from the window.
270174993Srafan   * Strip attributes and color from the string so they will not be added
271174993Srafan   * back when copying the string to the window.
272174993Srafan   */
273174993Srafan  for (x = 0; x < n; ++x)
274174993Srafan    {
275174993Srafan      RemAttr(s[x], A_ATTRIBUTES);
276174993Srafan      SetPair(s[x], 0);
277174993Srafan    }
278166124Srafan  return n;
279166124Srafan}
280166124Srafan
281166124Srafan/*
282166124Srafan * Returns the column of the base of the given cell.
283166124Srafan */
284166124Srafanstatic int
285166124Srafancell_base(WINDOW *win, int y, int x)
286166124Srafan{
287166124Srafan  int result = x;
288166124Srafan
289166124Srafan  while (LEGALYX(win, y, x))
290166124Srafan    {
291166124Srafan      cchar_t *data = &(win->_line[y].text[x]);
292166124Srafan
293166124Srafan      if (isWidecBase(CHDEREF(data)) || !isWidecExt(CHDEREF(data)))
294166124Srafan	{
295166124Srafan	  result = x;
296166124Srafan	  break;
297166124Srafan	}
298166124Srafan      --x;
299166124Srafan    }
300166124Srafan  return result;
301166124Srafan}
302166124Srafan
303166124Srafan/*
304166124Srafan * Returns the number of columns needed for the given cell in a window.
305166124Srafan */
306166124Srafanstatic int
307166124Srafancell_width(WINDOW *win, int y, int x)
308166124Srafan{
309166124Srafan  int result = 1;
310166124Srafan
311166124Srafan  if (LEGALYX(win, y, x))
312166124Srafan    {
313166124Srafan      cchar_t *data = &(win->_line[y].text[x]);
314166124Srafan
315166124Srafan      if (isWidecExt(CHDEREF(data)))
316166124Srafan	{
317166124Srafan	  /* recur, providing the number of columns to the next character */
318166124Srafan	  result = cell_width(win, y, x - 1);
319166124Srafan	}
320166124Srafan      else
321166124Srafan	{
322166124Srafan	  result = wcwidth(CharOf(CHDEREF(data)));
323166124Srafan	}
324166124Srafan    }
325166124Srafan  return result;
326166124Srafan}
327166124Srafan
328166124Srafan/*
329166124Srafan * There is no wide-character function such as wdel_wch(), so we must find
330166124Srafan * all of the cells that comprise a multi-column character and delete them
331166124Srafan * one-by-one.
332166124Srafan */
333166124Srafanstatic void
334166124Srafandelete_char(FORM *form)
335166124Srafan{
336166124Srafan  int cells = cell_width(form->w, form->currow, form->curcol);
337166124Srafan
338166124Srafan  form->curcol = cell_base(form->w, form->currow, form->curcol);
339166124Srafan  wmove(form->w, form->currow, form->curcol);
340166124Srafan  while (cells-- > 0)
341166124Srafan    {
342166124Srafan      wdelch(form->w);
343166124Srafan    }
344166124Srafan}
345166124Srafan#define DeleteChar(form) delete_char(form)
346166124Srafan#else
347166124Srafan#define DeleteChar(form) \
348166124Srafan	  wmove((form)->w, (form)->currow, (form)->curcol), \
349166124Srafan	  wdelch((form)->w)
350166124Srafan#endif
351166124Srafan
35250276Speter/*---------------------------------------------------------------------------
353166124Srafan|   Facility      :  libnform
35450276Speter|   Function      :  static char *Get_Start_Of_Data(char * buf, int blen)
355166124Srafan|
35650276Speter|   Description   :  Return pointer to first non-blank position in buffer.
35750276Speter|                    If buffer is empty return pointer to buffer itself.
35850276Speter|
35950276Speter|   Return Values :  Pointer to first non-blank position in buffer
36050276Speter+--------------------------------------------------------------------------*/
361166124SrafanNCURSES_INLINE static FIELD_CELL *
362166124SrafanGet_Start_Of_Data(FIELD_CELL *buf, int blen)
36350276Speter{
364166124Srafan  FIELD_CELL *p = buf;
365166124Srafan  FIELD_CELL *end = &buf[blen];
36650276Speter
367166124Srafan  assert(buf && blen >= 0);
368166124Srafan  while ((p < end) && ISBLANK(*p))
36950276Speter    p++;
370166124Srafan  return ((p == end) ? buf : p);
37150276Speter}
37250276Speter
37350276Speter/*---------------------------------------------------------------------------
374166124Srafan|   Facility      :  libnform
37550276Speter|   Function      :  static char *After_End_Of_Data(char * buf, int blen)
376166124Srafan|
37750276Speter|   Description   :  Return pointer after last non-blank position in buffer.
37850276Speter|                    If buffer is empty, return pointer to buffer itself.
37950276Speter|
380166124Srafan|   Return Values :  Pointer to position after last non-blank position in
38150276Speter|                    buffer.
38250276Speter+--------------------------------------------------------------------------*/
383166124SrafanNCURSES_INLINE static FIELD_CELL *
384166124SrafanAfter_End_Of_Data(FIELD_CELL *buf, int blen)
38550276Speter{
386166124Srafan  FIELD_CELL *p = &buf[blen];
387166124Srafan
388166124Srafan  assert(buf && blen >= 0);
389166124Srafan  while ((p > buf) && ISBLANK(p[-1]))
39050276Speter    p--;
391166124Srafan  return (p);
39250276Speter}
39350276Speter
39450276Speter/*---------------------------------------------------------------------------
395166124Srafan|   Facility      :  libnform
39650276Speter|   Function      :  static char *Get_First_Whitespace_Character(
39750276Speter|                                     char * buf, int   blen)
398166124Srafan|
39950276Speter|   Description   :  Position to the first whitespace character.
40050276Speter|
40150276Speter|   Return Values :  Pointer to first whitespace character in buffer.
40250276Speter+--------------------------------------------------------------------------*/
403166124SrafanNCURSES_INLINE static FIELD_CELL *
404166124SrafanGet_First_Whitespace_Character(FIELD_CELL *buf, int blen)
40550276Speter{
406166124Srafan  FIELD_CELL *p = buf;
407166124Srafan  FIELD_CELL *end = &p[blen];
408166124Srafan
409166124Srafan  assert(buf && blen >= 0);
410166124Srafan  while ((p < end) && !ISBLANK(*p))
41150276Speter    p++;
412166124Srafan  return ((p == end) ? buf : p);
41350276Speter}
41450276Speter
41550276Speter/*---------------------------------------------------------------------------
416166124Srafan|   Facility      :  libnform
41750276Speter|   Function      :  static char *After_Last_Whitespace_Character(
41850276Speter|                                     char * buf, int blen)
419166124Srafan|
42050276Speter|   Description   :  Get the position after the last whitespace character.
42150276Speter|
422166124Srafan|   Return Values :  Pointer to position after last whitespace character in
42350276Speter|                    buffer.
42450276Speter+--------------------------------------------------------------------------*/
425166124SrafanNCURSES_INLINE static FIELD_CELL *
426166124SrafanAfter_Last_Whitespace_Character(FIELD_CELL *buf, int blen)
42750276Speter{
428166124Srafan  FIELD_CELL *p = &buf[blen];
429166124Srafan
430166124Srafan  assert(buf && blen >= 0);
431166124Srafan  while ((p > buf) && !ISBLANK(p[-1]))
43250276Speter    p--;
433166124Srafan  return (p);
43450276Speter}
43550276Speter
43650276Speter/* Set this to 1 to use the div_t version. This is a good idea if your
43750276Speter   compiler has an intrinsic div() support. Unfortunately GNU-C has it
438166124Srafan   not yet.
43950276Speter   N.B.: This only works if form->curcol follows immediately form->currow
440166124Srafan         and both are of type int.
44150276Speter*/
44250276Speter#define USE_DIV_T (0)
44350276Speter
44450276Speter/*---------------------------------------------------------------------------
445166124Srafan|   Facility      :  libnform
44650276Speter|   Function      :  static void Adjust_Cursor_Position(
44750276Speter|                                       FORM * form, const char * pos)
448166124Srafan|
449166124Srafan|   Description   :  Set current row and column of the form to values
45050276Speter|                    corresponding to the buffer position.
45150276Speter|
45250276Speter|   Return Values :  -
45350276Speter+--------------------------------------------------------------------------*/
454166124SrafanNCURSES_INLINE static void
455166124SrafanAdjust_Cursor_Position(FORM *form, const FIELD_CELL *pos)
45650276Speter{
45750276Speter  FIELD *field;
45850276Speter  int idx;
45950276Speter
46050276Speter  field = form->current;
461166124Srafan  assert(pos >= field->buf && field->dcols > 0);
462166124Srafan  idx = (int)(pos - field->buf);
46350276Speter#if USE_DIV_T
464166124Srafan  *((div_t *) & (form->currow)) = div(idx, field->dcols);
46550276Speter#else
46650276Speter  form->currow = idx / field->dcols;
46750276Speter  form->curcol = idx - field->cols * form->currow;
468166124Srafan#endif
469166124Srafan  if (field->drows < form->currow)
47050276Speter    form->currow = 0;
47150276Speter}
47250276Speter
47350276Speter/*---------------------------------------------------------------------------
474166124Srafan|   Facility      :  libnform
47550276Speter|   Function      :  static void Buffer_To_Window(
47650276Speter|                                      const FIELD  * field,
47750276Speter|                                      WINDOW * win)
478166124Srafan|
479166124Srafan|   Description   :  Copy the buffer to the window. If it is a multi-line
48050276Speter|                    field, the buffer is split to the lines of the
48150276Speter|                    window without any editing.
48250276Speter|
48350276Speter|   Return Values :  -
48450276Speter+--------------------------------------------------------------------------*/
485166124Srafanstatic void
486166124SrafanBuffer_To_Window(const FIELD *field, WINDOW *win)
48750276Speter{
48850276Speter  int width, height;
489166124Srafan  int y, x;
49050276Speter  int len;
49150276Speter  int row;
492166124Srafan  FIELD_CELL *pBuffer;
49350276Speter
49450276Speter  assert(win && field);
49550276Speter
496166124Srafan  getyx(win, y, x);
497166124Srafan  width = getmaxx(win);
49850276Speter  height = getmaxy(win);
49950276Speter
500166124Srafan  for (row = 0, pBuffer = field->buf;
501166124Srafan       row < height;
502166124Srafan       row++, pBuffer += width)
50350276Speter    {
504166124Srafan      if ((len = (int)(After_End_Of_Data(pBuffer, width) - pBuffer)) > 0)
50550276Speter	{
506166124Srafan	  wmove(win, row, 0);
507166124Srafan	  myADDNSTR(win, pBuffer, len);
50850276Speter	}
509166124Srafan    }
510166124Srafan  wmove(win, y, x);
51150276Speter}
51250276Speter
51350276Speter/*---------------------------------------------------------------------------
514166124Srafan|   Facility      :  libnform
51550276Speter|   Function      :  static void Window_To_Buffer(
51650276Speter|                                          WINDOW * win,
51750276Speter|                                          FIELD  * field)
518166124Srafan|
51950276Speter|   Description   :  Copy the content of the window into the buffer.
52050276Speter|                    The multiple lines of a window are simply
52150276Speter|                    concatenated into the buffer. Pad characters in
52250276Speter|                    the window will be replaced by blanks in the buffer.
52350276Speter|
52450276Speter|   Return Values :  -
52550276Speter+--------------------------------------------------------------------------*/
526166124Srafanstatic void
527166124SrafanWindow_To_Buffer(WINDOW *win, FIELD *field)
52850276Speter{
52950276Speter  int pad;
53050276Speter  int len = 0;
531166124Srafan  FIELD_CELL *p;
53250276Speter  int row, height;
53350276Speter
534166124Srafan  assert(win && field && field->buf);
535166124Srafan
53650276Speter  pad = field->pad;
53750276Speter  p = field->buf;
53850276Speter  height = getmaxy(win);
53950276Speter
540166124Srafan  for (row = 0; (row < height) && (row < field->drows); row++)
54150276Speter    {
542166124Srafan      wmove(win, row, 0);
543166124Srafan      len += myINNSTR(win, p + len, field->dcols);
54450276Speter    }
545166124Srafan  p[len] = myZEROS;
54650276Speter
54750276Speter  /* replace visual padding character by blanks in buffer */
54850276Speter  if (pad != C_BLANK)
54950276Speter    {
55050276Speter      int i;
551166124Srafan
552166124Srafan      for (i = 0; i < len; i++, p++)
55350276Speter	{
554166124Srafan	  if ((unsigned long)CharOf(*p) == ChCharOf(pad)
555166124Srafan#if USE_WIDEC_SUPPORT
556166124Srafan	      && p->chars[1] == 0
557166124Srafan#endif
558166124Srafan	    )
559166124Srafan	    *p = myBLANK;
56050276Speter	}
56150276Speter    }
56250276Speter}
56350276Speter
56450276Speter/*---------------------------------------------------------------------------
565166124Srafan|   Facility      :  libnform
56650276Speter|   Function      :  static void Synchronize_Buffer(FORM * form)
567166124Srafan|
56850276Speter|   Description   :  If there was a change, copy the content of the
56950276Speter|                    window into the buffer, so the buffer is synchronized
57050276Speter|                    with the windows content. We have to indicate that the
57150276Speter|                    buffer needs validation due to the change.
57250276Speter|
57350276Speter|   Return Values :  -
57450276Speter+--------------------------------------------------------------------------*/
575166124SrafanNCURSES_INLINE static void
576166124SrafanSynchronize_Buffer(FORM *form)
57750276Speter{
57850276Speter  if (form->status & _WINDOW_MODIFIED)
57950276Speter    {
58050276Speter      form->status &= ~_WINDOW_MODIFIED;
581166124Srafan      form->status |= _FCHECK_REQUIRED;
582166124Srafan      Window_To_Buffer(form->w, form->current);
583166124Srafan      wmove(form->w, form->currow, form->curcol);
58450276Speter    }
58550276Speter}
58650276Speter
58750276Speter/*---------------------------------------------------------------------------
588166124Srafan|   Facility      :  libnform
58950276Speter|   Function      :  static bool Field_Grown( FIELD *field, int amount)
590166124Srafan|
59150276Speter|   Description   :  This function is called for growable dynamic fields
59250276Speter|                    only. It has to increase the buffers and to allocate
59350276Speter|                    a new window for this field.
59450276Speter|                    This function has the side effect to set a new
59550276Speter|                    field-buffer pointer, the dcols and drows values
59650276Speter|                    as well as a new current Window for the field.
59750276Speter|
59850276Speter|   Return Values :  TRUE     - field successfully increased
59950276Speter|                    FALSE    - there was some error
60050276Speter+--------------------------------------------------------------------------*/
601166124Srafanstatic bool
602166124SrafanField_Grown(FIELD *field, int amount)
60350276Speter{
60450276Speter  bool result = FALSE;
60550276Speter
60650276Speter  if (field && Growable(field))
60750276Speter    {
60850276Speter      bool single_line_field = Single_Line_Field(field);
60950276Speter      int old_buflen = Buffer_Length(field);
61050276Speter      int new_buflen;
61150276Speter      int old_dcols = field->dcols;
61250276Speter      int old_drows = field->drows;
613166124Srafan      FIELD_CELL *oldbuf = field->buf;
614166124Srafan      FIELD_CELL *newbuf;
61550276Speter
61650276Speter      int growth;
61750276Speter      FORM *form = field->form;
618166124Srafan      bool need_visual_update = ((form != (FORM *)0) &&
61950276Speter				 (form->status & _POSTED) &&
620166124Srafan				 (form->current == field));
621166124Srafan
62250276Speter      if (need_visual_update)
62350276Speter	Synchronize_Buffer(form);
624166124Srafan
62550276Speter      if (single_line_field)
62650276Speter	{
62750276Speter	  growth = field->cols * amount;
62850276Speter	  if (field->maxgrow)
629166124Srafan	    growth = Minimum(field->maxgrow - field->dcols, growth);
63050276Speter	  field->dcols += growth;
63150276Speter	  if (field->dcols == field->maxgrow)
63250276Speter	    field->status &= ~_MAY_GROW;
63350276Speter	}
63450276Speter      else
63550276Speter	{
63650276Speter	  growth = (field->rows + field->nrow) * amount;
63750276Speter	  if (field->maxgrow)
638166124Srafan	    growth = Minimum(field->maxgrow - field->drows, growth);
63950276Speter	  field->drows += growth;
64050276Speter	  if (field->drows == field->maxgrow)
64150276Speter	    field->status &= ~_MAY_GROW;
64250276Speter	}
64350276Speter      /* drows, dcols changed, so we get really the new buffer length */
64450276Speter      new_buflen = Buffer_Length(field);
645166124Srafan      newbuf = (FIELD_CELL *)malloc(Total_Buffer_Size(field));
64650276Speter      if (!newbuf)
647166124Srafan	{
648166124Srafan	  /* restore to previous state */
64950276Speter	  field->dcols = old_dcols;
65050276Speter	  field->drows = old_drows;
651166124Srafan	  if ((single_line_field && (field->dcols != field->maxgrow)) ||
652166124Srafan	      (!single_line_field && (field->drows != field->maxgrow)))
65350276Speter	    field->status |= _MAY_GROW;
65450276Speter	}
65550276Speter      else
656166124Srafan	{
657166124Srafan	  /* Copy all the buffers.  This is the reason why we can't just use
658166124Srafan	   * realloc().
659166124Srafan	   */
660166124Srafan	  int i, j;
661166124Srafan	  FIELD_CELL *old_bp;
662166124Srafan	  FIELD_CELL *new_bp;
663166124Srafan
664166124Srafan	  result = TRUE;	/* allow sharing of recovery on failure */
665166124Srafan
666174993Srafan	  T((T_CREATE("fieldcell %p"), newbuf));
66750276Speter	  field->buf = newbuf;
668166124Srafan	  for (i = 0; i <= field->nbuf; i++)
66950276Speter	    {
670166124Srafan	      new_bp = Address_Of_Nth_Buffer(field, i);
671166124Srafan	      old_bp = oldbuf + i * (1 + old_buflen);
672166124Srafan	      for (j = 0; j < old_buflen; ++j)
673166124Srafan		new_bp[j] = old_bp[j];
674166124Srafan	      while (j < new_buflen)
675166124Srafan		new_bp[j++] = myBLANK;
676166124Srafan	      new_bp[new_buflen] = myZEROS;
67750276Speter	    }
67850276Speter
679176187Srafan#if USE_WIDEC_SUPPORT && NCURSES_EXT_FUNCS
680166124Srafan	  if (wresize(field->working, 1, Buffer_Length(field) + 1) == ERR)
681166124Srafan	    result = FALSE;
682166124Srafan#endif
683166124Srafan
684166124Srafan	  if (need_visual_update && result)
685166124Srafan	    {
686166124Srafan	      WINDOW *new_window = newpad(field->drows, field->dcols);
687166124Srafan
688166124Srafan	      if (new_window != 0)
689166124Srafan		{
690166124Srafan		  assert(form != (FORM *)0);
691166124Srafan		  if (form->w)
692166124Srafan		    delwin(form->w);
693166124Srafan		  form->w = new_window;
694166124Srafan		  Set_Field_Window_Attributes(field, form->w);
695166124Srafan		  werase(form->w);
696166124Srafan		  Buffer_To_Window(field, form->w);
697166124Srafan		  untouchwin(form->w);
698166124Srafan		  wmove(form->w, form->currow, form->curcol);
69950276Speter		}
700166124Srafan	      else
701166124Srafan		result = FALSE;
70250276Speter	    }
70350276Speter
704166124Srafan	  if (result)
70550276Speter	    {
706166124Srafan	      free(oldbuf);
707166124Srafan	      /* reflect changes in linked fields */
708166124Srafan	      if (field != field->link)
70950276Speter		{
710166124Srafan		  FIELD *linked_field;
711166124Srafan
712166124Srafan		  for (linked_field = field->link;
713166124Srafan		       linked_field != field;
714166124Srafan		       linked_field = linked_field->link)
715166124Srafan		    {
716166124Srafan		      linked_field->buf = field->buf;
717166124Srafan		      linked_field->drows = field->drows;
718166124Srafan		      linked_field->dcols = field->dcols;
719166124Srafan		    }
72050276Speter		}
72150276Speter	    }
722166124Srafan	  else
723166124Srafan	    {
724166124Srafan	      /* restore old state */
725166124Srafan	      field->dcols = old_dcols;
726166124Srafan	      field->drows = old_drows;
727166124Srafan	      field->buf = oldbuf;
728166124Srafan	      if ((single_line_field &&
729166124Srafan		   (field->dcols != field->maxgrow)) ||
730166124Srafan		  (!single_line_field &&
731166124Srafan		   (field->drows != field->maxgrow)))
732166124Srafan		field->status |= _MAY_GROW;
733166124Srafan	      free(newbuf);
734166124Srafan	    }
735166124Srafan	}
73650276Speter    }
737166124Srafan  return (result);
73850276Speter}
73950276Speter
740174993Srafan#ifdef NCURSES_MOUSE_VERSION
74150276Speter/*---------------------------------------------------------------------------
742166124Srafan|   Facility      :  libnform
743174993Srafan|   Function      :  int Field_encloses(FIELD *field, int ry, int rx)
744174993Srafan|
745174993Srafan|   Description   :  Check if the given coordinates lie within the given field.
746174993Srafan|
747174993Srafan|   Return Values :  E_OK              - success
748174993Srafan|                    E_BAD_ARGUMENT    - invalid form pointer
749174993Srafan|                    E_SYSTEM_ERROR    - form has no current field or
750174993Srafan|                                        field-window
751174993Srafan+--------------------------------------------------------------------------*/
752174993Srafanstatic int
753174993SrafanField_encloses(FIELD *field, int ry, int rx)
754174993Srafan{
755174993Srafan  T((T_CALLED("Field_encloses(%p)"), field));
756174993Srafan  if (field != 0
757174993Srafan      && field->frow <= ry
758174993Srafan      && (field->frow + field->rows) > ry
759174993Srafan      && field->fcol <= rx
760174993Srafan      && (field->fcol + field->cols) > rx)
761174993Srafan    {
762174993Srafan      RETURN(E_OK);
763174993Srafan    }
764174993Srafan  RETURN(E_INVALID_FIELD);
765174993Srafan}
766174993Srafan#endif
767174993Srafan
768174993Srafan/*---------------------------------------------------------------------------
769174993Srafan|   Facility      :  libnform
77050276Speter|   Function      :  int _nc_Position_Form_Cursor(FORM * form)
771166124Srafan|
77250276Speter|   Description   :  Position the cursor in the window for the current
773166124Srafan|                    field to be in sync. with the currow and curcol
77450276Speter|                    values.
77550276Speter|
77650276Speter|   Return Values :  E_OK              - success
77750276Speter|                    E_BAD_ARGUMENT    - invalid form pointer
77850276Speter|                    E_SYSTEM_ERROR    - form has no current field or
77950276Speter|                                        field-window
78050276Speter+--------------------------------------------------------------------------*/
78176726SpeterNCURSES_EXPORT(int)
782166124Srafan_nc_Position_Form_Cursor(FORM *form)
78350276Speter{
784166124Srafan  FIELD *field;
78550276Speter  WINDOW *formwin;
786166124Srafan
78750276Speter  if (!form)
788166124Srafan    return (E_BAD_ARGUMENT);
78950276Speter
790166124Srafan  if (!form->w || !form->current)
791166124Srafan    return (E_SYSTEM_ERROR);
79250276Speter
793166124Srafan  field = form->current;
794166124Srafan  formwin = Get_Form_Window(form);
79550276Speter
796166124Srafan  wmove(form->w, form->currow, form->curcol);
797166124Srafan  if (Has_Invisible_Parts(field))
79850276Speter    {
79950276Speter      /* in this case fieldwin isn't derived from formwin, so we have
800166124Srafan         to move the cursor in formwin by hand... */
80150276Speter      wmove(formwin,
80250276Speter	    field->frow + form->currow - form->toprow,
80350276Speter	    field->fcol + form->curcol - form->begincol);
80450276Speter      wcursyncup(formwin);
80550276Speter    }
806166124Srafan  else
80750276Speter    wcursyncup(form->w);
808166124Srafan  return (E_OK);
80950276Speter}
81050276Speter
81150276Speter/*---------------------------------------------------------------------------
812166124Srafan|   Facility      :  libnform
81350276Speter|   Function      :  int _nc_Refresh_Current_Field(FORM * form)
814166124Srafan|
81550276Speter|   Description   :  Propagate the changes in the fields window to the
81650276Speter|                    window of the form.
81750276Speter|
81850276Speter|   Return Values :  E_OK              - on success
81950276Speter|                    E_BAD_ARGUMENT    - invalid form pointer
82050276Speter|                    E_SYSTEM_ERROR    - general error
82150276Speter+--------------------------------------------------------------------------*/
82276726SpeterNCURSES_EXPORT(int)
823166124Srafan_nc_Refresh_Current_Field(FORM *form)
82450276Speter{
82550276Speter  WINDOW *formwin;
826166124Srafan  FIELD *field;
82750276Speter
828166124Srafan  T((T_CALLED("_nc_Refresh_Current_Field(%p)"), form));
829166124Srafan
83050276Speter  if (!form)
83150276Speter    RETURN(E_BAD_ARGUMENT);
83250276Speter
833166124Srafan  if (!form->w || !form->current)
83450276Speter    RETURN(E_SYSTEM_ERROR);
83550276Speter
836166124Srafan  field = form->current;
837166124Srafan  formwin = Get_Form_Window(form);
83850276Speter
83950276Speter  if (field->opts & O_PUBLIC)
84050276Speter    {
84150276Speter      if (Is_Scroll_Field(field))
84250276Speter	{
84350276Speter	  /* Again, in this case the fieldwin isn't derived from formwin,
84450276Speter	     so we have to perform a copy operation. */
84550276Speter	  if (Single_Line_Field(field))
846166124Srafan	    {
847166124Srafan	      /* horizontal scrolling */
84850276Speter	      if (form->curcol < form->begincol)
849166124Srafan		form->begincol = form->curcol;
85050276Speter	      else
85150276Speter		{
85250276Speter		  if (form->curcol >= (form->begincol + field->cols))
853166124Srafan		    form->begincol = form->curcol - field->cols + 1;
85450276Speter		}
85550276Speter	      copywin(form->w,
85650276Speter		      formwin,
85750276Speter		      0,
85850276Speter		      form->begincol,
85950276Speter		      field->frow,
86050276Speter		      field->fcol,
86150276Speter		      field->frow,
86250276Speter		      field->cols + field->fcol - 1,
86350276Speter		      0);
86450276Speter	    }
86550276Speter	  else
866166124Srafan	    {
867166124Srafan	      /* A multi-line, i.e. vertical scrolling field */
868166124Srafan	      int row_after_bottom, first_modified_row, first_unmodified_row;
86950276Speter
87050276Speter	      if (field->drows > field->rows)
87150276Speter		{
87250276Speter		  row_after_bottom = form->toprow + field->rows;
87350276Speter		  if (form->currow < form->toprow)
87450276Speter		    {
87550276Speter		      form->toprow = form->currow;
87650276Speter		      field->status |= _NEWTOP;
87750276Speter		    }
87850276Speter		  if (form->currow >= row_after_bottom)
87950276Speter		    {
88050276Speter		      form->toprow = form->currow - field->rows + 1;
88150276Speter		      field->status |= _NEWTOP;
88250276Speter		    }
88350276Speter		  if (field->status & _NEWTOP)
884166124Srafan		    {
885166124Srafan		      /* means we have to copy whole range */
88650276Speter		      first_modified_row = form->toprow;
88750276Speter		      first_unmodified_row = first_modified_row + field->rows;
88850276Speter		      field->status &= ~_NEWTOP;
88950276Speter		    }
890166124Srafan		  else
891166124Srafan		    {
892166124Srafan		      /* we try to optimize : finding the range of touched
893166124Srafan		         lines */
89450276Speter		      first_modified_row = form->toprow;
895166124Srafan		      while (first_modified_row < row_after_bottom)
89650276Speter			{
897166124Srafan			  if (is_linetouched(form->w, first_modified_row))
89850276Speter			    break;
89950276Speter			  first_modified_row++;
90050276Speter			}
90150276Speter		      first_unmodified_row = first_modified_row;
902166124Srafan		      while (first_unmodified_row < row_after_bottom)
90350276Speter			{
904166124Srafan			  if (!is_linetouched(form->w, first_unmodified_row))
90550276Speter			    break;
90650276Speter			  first_unmodified_row++;
90750276Speter			}
90850276Speter		    }
90950276Speter		}
91050276Speter	      else
91150276Speter		{
912166124Srafan		  first_modified_row = form->toprow;
91350276Speter		  first_unmodified_row = first_modified_row + field->rows;
91450276Speter		}
91550276Speter	      if (first_unmodified_row != first_modified_row)
91650276Speter		copywin(form->w,
91750276Speter			formwin,
91850276Speter			first_modified_row,
91950276Speter			0,
92050276Speter			field->frow + first_modified_row - form->toprow,
92150276Speter			field->fcol,
92250276Speter			field->frow + first_unmodified_row - form->toprow - 1,
92350276Speter			field->cols + field->fcol - 1,
92450276Speter			0);
92550276Speter	    }
92650276Speter	  wsyncup(formwin);
92750276Speter	}
92850276Speter      else
929166124Srafan	{
930166124Srafan	  /* if the field-window is simply a derived window, i.e. contains no
931166124Srafan	   * invisible parts, the whole thing is trivial
932166124Srafan	   */
93350276Speter	  wsyncup(form->w);
93450276Speter	}
93550276Speter    }
93650276Speter  untouchwin(form->w);
937166124Srafan  returnCode(_nc_Position_Form_Cursor(form));
93850276Speter}
939166124Srafan
94050276Speter/*---------------------------------------------------------------------------
941166124Srafan|   Facility      :  libnform
94250276Speter|   Function      :  static void Perform_Justification(
94350276Speter|                                        FIELD  * field,
94450276Speter|                                        WINDOW * win)
94550276Speter|
946166124Srafan|   Description   :  Output field with requested justification
947166124Srafan|
94850276Speter|   Return Values :  -
94950276Speter+--------------------------------------------------------------------------*/
950166124Srafanstatic void
951166124SrafanPerform_Justification(FIELD *field, WINDOW *win)
95250276Speter{
953166124Srafan  FIELD_CELL *bp;
95450276Speter  int len;
955166124Srafan  int col = 0;
95650276Speter
957166124Srafan  bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
958166124Srafan  len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
95950276Speter
960166124Srafan  if (len > 0)
96150276Speter    {
96250276Speter      assert(win && (field->drows == 1) && (field->dcols == field->cols));
96350276Speter
964166124Srafan      switch (field->just)
96550276Speter	{
96650276Speter	case JUSTIFY_LEFT:
96750276Speter	  break;
96850276Speter	case JUSTIFY_CENTER:
969166124Srafan	  col = (field->cols - len) / 2;
97050276Speter	  break;
97150276Speter	case JUSTIFY_RIGHT:
97250276Speter	  col = field->cols - len;
97350276Speter	  break;
97450276Speter	default:
97550276Speter	  break;
97650276Speter	}
97750276Speter
978166124Srafan      wmove(win, 0, col);
979166124Srafan      myADDNSTR(win, bp, len);
98050276Speter    }
98150276Speter}
98250276Speter
98350276Speter/*---------------------------------------------------------------------------
984166124Srafan|   Facility      :  libnform
98550276Speter|   Function      :  static void Undo_Justification(
98650276Speter|                                     FIELD  * field,
98750276Speter|                                     WINDOW * win)
988166124Srafan|
98950276Speter|   Description   :  Display field without any justification, i.e.
99050276Speter|                    left justified
99150276Speter|
99250276Speter|   Return Values :  -
99350276Speter+--------------------------------------------------------------------------*/
994166124Srafanstatic void
995166124SrafanUndo_Justification(FIELD *field, WINDOW *win)
99650276Speter{
997166124Srafan  FIELD_CELL *bp;
99850276Speter  int len;
99950276Speter
1000166124Srafan  bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
1001166124Srafan  len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
100250276Speter
1003166124Srafan  if (len > 0)
100450276Speter    {
100550276Speter      assert(win);
1006166124Srafan      wmove(win, 0, 0);
1007166124Srafan      myADDNSTR(win, bp, len);
100850276Speter    }
100950276Speter}
101050276Speter
101150276Speter/*---------------------------------------------------------------------------
1012166124Srafan|   Facility      :  libnform
101350276Speter|   Function      :  static bool Check_Char(
101450276Speter|                                           FIELDTYPE * typ,
101550276Speter|                                           int ch,
101650276Speter|                                           TypeArgument *argp)
1017166124Srafan|
101850276Speter|   Description   :  Perform a single character check for character ch
1019166124Srafan|                    according to the fieldtype instance.
102050276Speter|
102150276Speter|   Return Values :  TRUE             - Character is valid
102250276Speter|                    FALSE            - Character is invalid
102350276Speter+--------------------------------------------------------------------------*/
1024166124Srafanstatic bool
1025166124SrafanCheck_Char(FIELDTYPE *typ, int ch, TypeArgument *argp)
102650276Speter{
1027166124Srafan  if (typ)
102850276Speter    {
102950276Speter      if (typ->status & _LINKED_TYPE)
103050276Speter	{
103150276Speter	  assert(argp);
1032166124Srafan	  return (
1033166124Srafan		   Check_Char(typ->left, ch, argp->left) ||
1034166124Srafan		   Check_Char(typ->right, ch, argp->right));
1035166124Srafan	}
1036166124Srafan      else
103750276Speter	{
103850276Speter	  if (typ->ccheck)
1039166124Srafan	    return typ->ccheck(ch, (void *)argp);
104050276Speter	}
104150276Speter    }
1042166124Srafan  return (!iscntrl(UChar(ch)) ? TRUE : FALSE);
104350276Speter}
104450276Speter
104550276Speter/*---------------------------------------------------------------------------
1046166124Srafan|   Facility      :  libnform
104750276Speter|   Function      :  static int Display_Or_Erase_Field(
104850276Speter|                                           FIELD * field,
104950276Speter|                                           bool bEraseFlag)
1050166124Srafan|
105150276Speter|   Description   :  Create a subwindow for the field and display the
105250276Speter|                    buffer contents (apply justification if required)
105350276Speter|                    or simply erase the field.
105450276Speter|
105550276Speter|   Return Values :  E_OK           - on success
105650276Speter|                    E_SYSTEM_ERROR - some error (typical no memory)
105750276Speter+--------------------------------------------------------------------------*/
1058166124Srafanstatic int
1059166124SrafanDisplay_Or_Erase_Field(FIELD *field, bool bEraseFlag)
106050276Speter{
106150276Speter  WINDOW *win;
106250276Speter  WINDOW *fwin;
106350276Speter
106450276Speter  if (!field)
106550276Speter    return E_SYSTEM_ERROR;
106650276Speter
106750276Speter  fwin = Get_Form_Window(field->form);
1068166124Srafan  win = derwin(fwin,
1069166124Srafan	       field->rows, field->cols, field->frow, field->fcol);
107050276Speter
1071166124Srafan  if (!win)
107250276Speter    return E_SYSTEM_ERROR;
107350276Speter  else
107450276Speter    {
107550276Speter      if (field->opts & O_VISIBLE)
1076166124Srafan	Set_Field_Window_Attributes(field, win);
107750276Speter      else
1078166124Srafan	wattrset(win, WINDOW_ATTRS(fwin));
107950276Speter      werase(win);
108050276Speter    }
108150276Speter
108250276Speter  if (!bEraseFlag)
108350276Speter    {
108450276Speter      if (field->opts & O_PUBLIC)
108550276Speter	{
108650276Speter	  if (Justification_Allowed(field))
1087166124Srafan	    Perform_Justification(field, win);
108850276Speter	  else
1089166124Srafan	    Buffer_To_Window(field, win);
109050276Speter	}
109150276Speter      field->status &= ~_NEWTOP;
109250276Speter    }
109350276Speter  wsyncup(win);
109450276Speter  delwin(win);
109550276Speter  return E_OK;
109650276Speter}
109750276Speter
109850276Speter/* Macros to preset the bEraseFlag */
109950276Speter#define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
110050276Speter#define Erase_Field(field)   Display_Or_Erase_Field(field,TRUE)
110150276Speter
110250276Speter/*---------------------------------------------------------------------------
1103166124Srafan|   Facility      :  libnform
110450276Speter|   Function      :  static int Synchronize_Field(FIELD * field)
1105166124Srafan|
110650276Speter|   Description   :  Synchronize the windows content with the value in
110750276Speter|                    the buffer.
110850276Speter|
110950276Speter|   Return Values :  E_OK                - success
1110166124Srafan|                    E_BAD_ARGUMENT      - invalid field pointer
111150276Speter|                    E_SYSTEM_ERROR      - some severe basic error
111250276Speter+--------------------------------------------------------------------------*/
1113166124Srafanstatic int
1114166124SrafanSynchronize_Field(FIELD *field)
111550276Speter{
111650276Speter  FORM *form;
111750276Speter  int res = E_OK;
111850276Speter
111950276Speter  if (!field)
1120166124Srafan    return (E_BAD_ARGUMENT);
112150276Speter
1122166124Srafan  if (((form = field->form) != (FORM *)0)
112350276Speter      && Field_Really_Appears(field))
112450276Speter    {
112550276Speter      if (field == form->current)
1126166124Srafan	{
1127166124Srafan	  form->currow = form->curcol = form->toprow = form->begincol = 0;
112850276Speter	  werase(form->w);
1129166124Srafan
1130166124Srafan	  if ((field->opts & O_PUBLIC) && Justification_Allowed(field))
1131166124Srafan	    Undo_Justification(field, form->w);
113250276Speter	  else
1133166124Srafan	    Buffer_To_Window(field, form->w);
1134166124Srafan
113550276Speter	  field->status |= _NEWTOP;
1136166124Srafan	  res = _nc_Refresh_Current_Field(form);
113750276Speter	}
113850276Speter      else
1139166124Srafan	res = Display_Field(field);
114050276Speter    }
114150276Speter  field->status |= _CHANGED;
1142166124Srafan  return (res);
114350276Speter}
114450276Speter
114550276Speter/*---------------------------------------------------------------------------
1146166124Srafan|   Facility      :  libnform
114750276Speter|   Function      :  static int Synchronize_Linked_Fields(FIELD * field)
1148166124Srafan|
114950276Speter|   Description   :  Propagate the Synchronize_Field function to all linked
115050276Speter|                    fields. The first error that occurs in the sequence
1151166124Srafan|                    of updates is the return value.
115250276Speter|
115350276Speter|   Return Values :  E_OK                - success
1154166124Srafan|                    E_BAD_ARGUMENT      - invalid field pointer
115550276Speter|                    E_SYSTEM_ERROR      - some severe basic error
115650276Speter+--------------------------------------------------------------------------*/
1157166124Srafanstatic int
1158166124SrafanSynchronize_Linked_Fields(FIELD *field)
115950276Speter{
116050276Speter  FIELD *linked_field;
116150276Speter  int res = E_OK;
116250276Speter  int syncres;
116350276Speter
116450276Speter  if (!field)
1165166124Srafan    return (E_BAD_ARGUMENT);
116650276Speter
116750276Speter  if (!field->link)
1168166124Srafan    return (E_SYSTEM_ERROR);
116950276Speter
1170166124Srafan  for (linked_field = field->link;
1171166124Srafan       linked_field != field;
1172166124Srafan       linked_field = linked_field->link)
117350276Speter    {
1174166124Srafan      if (((syncres = Synchronize_Field(linked_field)) != E_OK) &&
1175166124Srafan	  (res == E_OK))
117650276Speter	res = syncres;
117750276Speter    }
1178166124Srafan  return (res);
117950276Speter}
118050276Speter
118150276Speter/*---------------------------------------------------------------------------
1182166124Srafan|   Facility      :  libnform
118350276Speter|   Function      :  int _nc_Synchronize_Attributes(FIELD * field)
1184166124Srafan|
118550276Speter|   Description   :  If a fields visual attributes have changed, this
118650276Speter|                    routine is called to propagate those changes to the
1187166124Srafan|                    screen.
118850276Speter|
118950276Speter|   Return Values :  E_OK             - success
119050276Speter|                    E_BAD_ARGUMENT   - invalid field pointer
119150276Speter|                    E_SYSTEM_ERROR   - some severe basic error
119250276Speter+--------------------------------------------------------------------------*/
119376726SpeterNCURSES_EXPORT(int)
1194166124Srafan_nc_Synchronize_Attributes(FIELD *field)
119550276Speter{
119650276Speter  FORM *form;
119750276Speter  int res = E_OK;
119850276Speter  WINDOW *formwin;
119950276Speter
1200166124Srafan  T((T_CALLED("_nc_Synchronize_Attributes(%p)"), field));
1201166124Srafan
120250276Speter  if (!field)
1203166124Srafan    returnCode(E_BAD_ARGUMENT);
120450276Speter
1205166124Srafan  CHECKPOS(field->form);
1206166124Srafan  if (((form = field->form) != (FORM *)0)
120750276Speter      && Field_Really_Appears(field))
1208166124Srafan    {
1209166124Srafan      if (form->current == field)
121050276Speter	{
121150276Speter	  Synchronize_Buffer(form);
1212166124Srafan	  Set_Field_Window_Attributes(field, form->w);
121350276Speter	  werase(form->w);
1214166124Srafan	  wmove(form->w, form->currow, form->curcol);
1215166124Srafan
121650276Speter	  if (field->opts & O_PUBLIC)
121750276Speter	    {
121850276Speter	      if (Justification_Allowed(field))
1219166124Srafan		Undo_Justification(field, form->w);
1220166124Srafan	      else
1221166124Srafan		Buffer_To_Window(field, form->w);
122250276Speter	    }
1223166124Srafan	  else
122450276Speter	    {
1225166124Srafan	      formwin = Get_Form_Window(form);
1226166124Srafan	      copywin(form->w, formwin,
1227166124Srafan		      0, 0,
1228166124Srafan		      field->frow, field->fcol,
1229166124Srafan		      field->rows - 1, field->cols - 1, 0);
123050276Speter	      wsyncup(formwin);
1231166124Srafan	      Buffer_To_Window(field, form->w);
1232166124Srafan	      field->status |= _NEWTOP;		/* fake refresh to paint all */
123350276Speter	      _nc_Refresh_Current_Field(form);
123450276Speter	    }
123550276Speter	}
1236166124Srafan      else
123750276Speter	{
123850276Speter	  res = Display_Field(field);
123950276Speter	}
124050276Speter    }
1241166124Srafan  CHECKPOS(form);
1242166124Srafan  returnCode(res);
124350276Speter}
124450276Speter
124550276Speter/*---------------------------------------------------------------------------
1246166124Srafan|   Facility      :  libnform
124750276Speter|   Function      :  int _nc_Synchronize_Options(FIELD * field,
124850276Speter|                                                Field_Options newopts)
1249166124Srafan|
125050276Speter|   Description   :  If a fields options have changed, this routine is
125150276Speter|                    called to propagate these changes to the screen and
1252166124Srafan|                    to really change the behavior of the field.
125350276Speter|
125450276Speter|   Return Values :  E_OK                - success
1255166124Srafan|                    E_BAD_ARGUMENT      - invalid field pointer
1256166124Srafan|                    E_CURRENT           - field is the current one
125750276Speter|                    E_SYSTEM_ERROR      - some severe basic error
125850276Speter+--------------------------------------------------------------------------*/
125976726SpeterNCURSES_EXPORT(int)
1260166124Srafan_nc_Synchronize_Options(FIELD *field, Field_Options newopts)
126150276Speter{
126250276Speter  Field_Options oldopts;
126350276Speter  Field_Options changed_opts;
126450276Speter  FORM *form;
126550276Speter  int res = E_OK;
126650276Speter
1267166124Srafan  T((T_CALLED("_nc_Synchronize_Options(%p,%#x)"), field, newopts));
1268166124Srafan
126950276Speter  if (!field)
1270166124Srafan    returnCode(E_BAD_ARGUMENT);
127150276Speter
1272166124Srafan  oldopts = field->opts;
127350276Speter  changed_opts = oldopts ^ newopts;
1274166124Srafan  field->opts = newopts;
1275166124Srafan  form = field->form;
127650276Speter
127750276Speter  if (form)
127850276Speter    {
127950276Speter      if (form->current == field)
128050276Speter	{
128150276Speter	  field->opts = oldopts;
1282166124Srafan	  returnCode(E_CURRENT);
128350276Speter	}
128450276Speter
128550276Speter      if (form->status & _POSTED)
128650276Speter	{
128750276Speter	  if ((form->curpage == field->page))
128850276Speter	    {
128950276Speter	      if (changed_opts & O_VISIBLE)
129050276Speter		{
129150276Speter		  if (newopts & O_VISIBLE)
129250276Speter		    res = Display_Field(field);
129350276Speter		  else
129450276Speter		    res = Erase_Field(field);
129550276Speter		}
129650276Speter	      else
129750276Speter		{
129850276Speter		  if ((changed_opts & O_PUBLIC) &&
129950276Speter		      (newopts & O_VISIBLE))
130050276Speter		    res = Display_Field(field);
130150276Speter		}
130250276Speter	    }
130350276Speter	}
130450276Speter    }
130550276Speter
130650276Speter  if (changed_opts & O_STATIC)
130750276Speter    {
130850276Speter      bool single_line_field = Single_Line_Field(field);
130950276Speter      int res2 = E_OK;
131050276Speter
131150276Speter      if (newopts & O_STATIC)
1312166124Srafan	{
1313166124Srafan	  /* the field becomes now static */
131450276Speter	  field->status &= ~_MAY_GROW;
131550276Speter	  /* if actually we have no hidden columns, justification may
131650276Speter	     occur again */
1317166124Srafan	  if (single_line_field &&
1318166124Srafan	      (field->cols == field->dcols) &&
131950276Speter	      (field->just != NO_JUSTIFICATION) &&
132050276Speter	      Field_Really_Appears(field))
132150276Speter	    {
132250276Speter	      res2 = Display_Field(field);
132350276Speter	    }
132450276Speter	}
132550276Speter      else
1326166124Srafan	{
1327166124Srafan	  /* field is no longer static */
1328166124Srafan	  if ((field->maxgrow == 0) ||
1329166124Srafan	      (single_line_field && (field->dcols < field->maxgrow)) ||
133050276Speter	      (!single_line_field && (field->drows < field->maxgrow)))
133150276Speter	    {
133250276Speter	      field->status |= _MAY_GROW;
1333166124Srafan	      /* a field with justification now changes its behavior,
1334166124Srafan	         so we must redisplay it */
1335166124Srafan	      if (single_line_field &&
133650276Speter		  (field->just != NO_JUSTIFICATION) &&
133750276Speter		  Field_Really_Appears(field))
133850276Speter		{
133950276Speter		  res2 = Display_Field(field);
1340166124Srafan		}
1341166124Srafan	    }
134250276Speter	}
134350276Speter      if (res2 != E_OK)
134450276Speter	res = res2;
134550276Speter    }
134650276Speter
1347166124Srafan  returnCode(res);
134850276Speter}
134950276Speter
135050276Speter/*---------------------------------------------------------------------------
1351166124Srafan|   Facility      :  libnform
135250276Speter|   Function      :  int _nc_Set_Current_Field(FORM  * form,
135350276Speter|                                              FIELD * newfield)
1354166124Srafan|
135550276Speter|   Description   :  Make the newfield the new current field.
135650276Speter|
1357166124Srafan|   Return Values :  E_OK              - success
1358166124Srafan|                    E_BAD_ARGUMENT    - invalid form or field pointer
1359166124Srafan|                    E_SYSTEM_ERROR    - some severe basic error
1360166124Srafan|                    E_NOT_CONNECTED   - no fields are connected to the form
136150276Speter+--------------------------------------------------------------------------*/
136276726SpeterNCURSES_EXPORT(int)
1363166124Srafan_nc_Set_Current_Field(FORM *form, FIELD *newfield)
136450276Speter{
1365166124Srafan  FIELD *field;
136650276Speter  WINDOW *new_window;
136750276Speter
1368166124Srafan  T((T_CALLED("_nc_Set_Current_Field(%p,%p)"), form, newfield));
136950276Speter
1370166124Srafan  if (!form || !newfield || !form->current || (newfield->form != form))
1371166124Srafan    returnCode(E_BAD_ARGUMENT);
137250276Speter
1373166124Srafan  if ((form->status & _IN_DRIVER))
1374166124Srafan    returnCode(E_BAD_STATE);
1375166124Srafan
137650276Speter  if (!(form->field))
1377166124Srafan    returnCode(E_NOT_CONNECTED);
137850276Speter
137950276Speter  field = form->current;
1380166124Srafan
1381166124Srafan  if ((field != newfield) ||
138250276Speter      !(form->status & _POSTED))
138350276Speter    {
1384166124Srafan      if ((form->w) &&
138550276Speter	  (field->opts & O_VISIBLE) &&
138650276Speter	  (field->form->curpage == field->page))
138750276Speter	{
138850276Speter	  _nc_Refresh_Current_Field(form);
138950276Speter	  if (field->opts & O_PUBLIC)
139050276Speter	    {
139150276Speter	      if (field->drows > field->rows)
139250276Speter		{
1393166124Srafan		  if (form->toprow == 0)
139450276Speter		    field->status &= ~_NEWTOP;
1395166124Srafan		  else
139650276Speter		    field->status |= _NEWTOP;
1397166124Srafan		}
1398166124Srafan	      else
139950276Speter		{
140050276Speter		  if (Justification_Allowed(field))
140150276Speter		    {
1402166124Srafan		      Window_To_Buffer(form->w, field);
140350276Speter		      werase(form->w);
1404166124Srafan		      Perform_Justification(field, form->w);
140550276Speter		      wsyncup(form->w);
140650276Speter		    }
140750276Speter		}
140850276Speter	    }
140950276Speter	  delwin(form->w);
141076726Speter	  form->w = (WINDOW *)0;
141150276Speter	}
1412166124Srafan
141350276Speter      field = newfield;
141450276Speter
141550276Speter      if (Has_Invisible_Parts(field))
1416166124Srafan	new_window = newpad(field->drows, field->dcols);
1417166124Srafan      else
141850276Speter	new_window = derwin(Get_Form_Window(form),
1419166124Srafan			    field->rows, field->cols, field->frow, field->fcol);
142050276Speter
1421166124Srafan      if (!new_window)
1422166124Srafan	returnCode(E_SYSTEM_ERROR);
142350276Speter
142450276Speter      form->current = field;
142576726Speter
142676726Speter      if (form->w)
142776726Speter	delwin(form->w);
1428166124Srafan      form->w = new_window;
142976726Speter
143050276Speter      form->status &= ~_WINDOW_MODIFIED;
1431166124Srafan      Set_Field_Window_Attributes(field, form->w);
143250276Speter
143350276Speter      if (Has_Invisible_Parts(field))
143450276Speter	{
143550276Speter	  werase(form->w);
1436166124Srafan	  Buffer_To_Window(field, form->w);
1437166124Srafan	}
1438166124Srafan      else
143950276Speter	{
144050276Speter	  if (Justification_Allowed(field))
144150276Speter	    {
144250276Speter	      werase(form->w);
1443166124Srafan	      Undo_Justification(field, form->w);
144450276Speter	      wsyncup(form->w);
144550276Speter	    }
144650276Speter	}
144750276Speter
144850276Speter      untouchwin(form->w);
144950276Speter    }
145050276Speter
145150276Speter  form->currow = form->curcol = form->toprow = form->begincol = 0;
1452166124Srafan  returnCode(E_OK);
145350276Speter}
1454166124Srafan
145550276Speter/*----------------------------------------------------------------------------
145650276Speter  Intra-Field Navigation routines
145750276Speter  --------------------------------------------------------------------------*/
145850276Speter
145950276Speter/*---------------------------------------------------------------------------
1460166124Srafan|   Facility      :  libnform
146150276Speter|   Function      :  static int IFN_Next_Character(FORM * form)
1462166124Srafan|
1463166124Srafan|   Description   :  Move to the next character in the field. In a multi-line
146450276Speter|                    field this wraps at the end of the line.
146550276Speter|
146650276Speter|   Return Values :  E_OK                - success
146750276Speter|                    E_REQUEST_DENIED    - at the rightmost position
146850276Speter+--------------------------------------------------------------------------*/
1469166124Srafanstatic int
1470166124SrafanIFN_Next_Character(FORM *form)
147150276Speter{
147250276Speter  FIELD *field = form->current;
1473166124Srafan  int step = myWCWIDTH(form->w, form->currow, form->curcol);
1474166124Srafan
1475166124Srafan  T((T_CALLED("IFN_Next_Character(%p)"), form));
1476166124Srafan  if ((form->curcol += step) == field->dcols)
147750276Speter    {
1478166124Srafan      if ((++(form->currow)) == field->drows)
147950276Speter	{
148050276Speter#if GROW_IF_NAVIGATE
1481166124Srafan	  if (!Single_Line_Field(field) && Field_Grown(field, 1))
1482166124Srafan	    {
1483166124Srafan	      form->curcol = 0;
1484166124Srafan	      returnCode(E_OK);
1485166124Srafan	    }
148650276Speter#endif
148750276Speter	  form->currow--;
148850276Speter#if GROW_IF_NAVIGATE
1489166124Srafan	  if (Single_Line_Field(field) && Field_Grown(field, 1))
1490166124Srafan	    returnCode(E_OK);
149150276Speter#endif
1492166124Srafan	  form->curcol -= step;
1493166124Srafan	  returnCode(E_REQUEST_DENIED);
149450276Speter	}
149550276Speter      form->curcol = 0;
149650276Speter    }
1497166124Srafan  returnCode(E_OK);
149850276Speter}
149950276Speter
150050276Speter/*---------------------------------------------------------------------------
1501166124Srafan|   Facility      :  libnform
150250276Speter|   Function      :  static int IFN_Previous_Character(FORM * form)
1503166124Srafan|
1504166124Srafan|   Description   :  Move to the previous character in the field. In a
1505166124Srafan|                    multi-line field this wraps and the beginning of the
150650276Speter|                    line.
150750276Speter|
150850276Speter|   Return Values :  E_OK                - success
150950276Speter|                    E_REQUEST_DENIED    - at the leftmost position
151050276Speter+--------------------------------------------------------------------------*/
1511166124Srafanstatic int
1512166124SrafanIFN_Previous_Character(FORM *form)
151350276Speter{
1514166124Srafan  int amount = myWCWIDTH(form->w, form->currow, form->curcol - 1);
1515166124Srafan  int oldcol = form->curcol;
1516166124Srafan
1517166124Srafan  T((T_CALLED("IFN_Previous_Character(%p)"), form));
1518166124Srafan  if ((form->curcol -= amount) < 0)
151950276Speter    {
1520166124Srafan      if ((--(form->currow)) < 0)
152150276Speter	{
152250276Speter	  form->currow++;
1523166124Srafan	  form->curcol = oldcol;
1524166124Srafan	  returnCode(E_REQUEST_DENIED);
152550276Speter	}
152650276Speter      form->curcol = form->current->dcols - 1;
152750276Speter    }
1528166124Srafan  returnCode(E_OK);
152950276Speter}
153050276Speter
153150276Speter/*---------------------------------------------------------------------------
1532166124Srafan|   Facility      :  libnform
153350276Speter|   Function      :  static int IFN_Next_Line(FORM * form)
1534166124Srafan|
153550276Speter|   Description   :  Move to the beginning of the next line in the field
153650276Speter|
153750276Speter|   Return Values :  E_OK                - success
153850276Speter|                    E_REQUEST_DENIED    - at the last line
153950276Speter+--------------------------------------------------------------------------*/
1540166124Srafanstatic int
1541166124SrafanIFN_Next_Line(FORM *form)
154250276Speter{
154350276Speter  FIELD *field = form->current;
154450276Speter
1545166124Srafan  T((T_CALLED("IFN_Next_Line(%p)"), form));
1546166124Srafan  if ((++(form->currow)) == field->drows)
154750276Speter    {
154850276Speter#if GROW_IF_NAVIGATE
1549166124Srafan      if (!Single_Line_Field(field) && Field_Grown(field, 1))
1550166124Srafan	returnCode(E_OK);
155150276Speter#endif
155250276Speter      form->currow--;
1553166124Srafan      returnCode(E_REQUEST_DENIED);
155450276Speter    }
155550276Speter  form->curcol = 0;
1556166124Srafan  returnCode(E_OK);
155750276Speter}
155850276Speter
155950276Speter/*---------------------------------------------------------------------------
1560166124Srafan|   Facility      :  libnform
156150276Speter|   Function      :  static int IFN_Previous_Line(FORM * form)
1562166124Srafan|
156350276Speter|   Description   :  Move to the beginning of the previous line in the field
156450276Speter|
156550276Speter|   Return Values :  E_OK                - success
156650276Speter|                    E_REQUEST_DENIED    - at the first line
156750276Speter+--------------------------------------------------------------------------*/
1568166124Srafanstatic int
1569166124SrafanIFN_Previous_Line(FORM *form)
157050276Speter{
1571166124Srafan  T((T_CALLED("IFN_Previous_Line(%p)"), form));
1572166124Srafan  if ((--(form->currow)) < 0)
157350276Speter    {
157450276Speter      form->currow++;
1575166124Srafan      returnCode(E_REQUEST_DENIED);
157650276Speter    }
157750276Speter  form->curcol = 0;
1578166124Srafan  returnCode(E_OK);
157950276Speter}
158050276Speter
158150276Speter/*---------------------------------------------------------------------------
1582166124Srafan|   Facility      :  libnform
158350276Speter|   Function      :  static int IFN_Next_Word(FORM * form)
1584166124Srafan|
158550276Speter|   Description   :  Move to the beginning of the next word in the field.
158650276Speter|
158750276Speter|   Return Values :  E_OK             - success
158850276Speter|                    E_REQUEST_DENIED - there is no next word
158950276Speter+--------------------------------------------------------------------------*/
1590166124Srafanstatic int
1591166124SrafanIFN_Next_Word(FORM *form)
159250276Speter{
159350276Speter  FIELD *field = form->current;
1594166124Srafan  FIELD_CELL *bp = Address_Of_Current_Position_In_Buffer(form);
1595166124Srafan  FIELD_CELL *s;
1596166124Srafan  FIELD_CELL *t;
159750276Speter
1598166124Srafan  T((T_CALLED("IFN_Next_Word(%p)"), form));
1599166124Srafan
160050276Speter  /* We really need access to the data, so we have to synchronize */
160150276Speter  Synchronize_Buffer(form);
160250276Speter
160350276Speter  /* Go to the first whitespace after the current position (including
1604166124Srafan     current position). This is then the starting point to look for the
1605166124Srafan     next non-blank data */
1606166124Srafan  s = Get_First_Whitespace_Character(bp, Buffer_Length(field) -
160750276Speter				     (int)(bp - field->buf));
160850276Speter
160950276Speter  /* Find the start of the next word */
1610166124Srafan  t = Get_Start_Of_Data(s, Buffer_Length(field) -
161150276Speter			(int)(s - field->buf));
161250276Speter#if !FRIENDLY_PREV_NEXT_WORD
1613166124Srafan  if (s == t)
1614166124Srafan    returnCode(E_REQUEST_DENIED);
161550276Speter  else
161650276Speter#endif
161750276Speter    {
1618166124Srafan      Adjust_Cursor_Position(form, t);
1619166124Srafan      returnCode(E_OK);
162050276Speter    }
162150276Speter}
162250276Speter
162350276Speter/*---------------------------------------------------------------------------
1624166124Srafan|   Facility      :  libnform
162550276Speter|   Function      :  static int IFN_Previous_Word(FORM * form)
1626166124Srafan|
162750276Speter|   Description   :  Move to the beginning of the previous word in the field.
162850276Speter|
162950276Speter|   Return Values :  E_OK             - success
163050276Speter|                    E_REQUEST_DENIED - there is no previous word
163150276Speter+--------------------------------------------------------------------------*/
1632166124Srafanstatic int
1633166124SrafanIFN_Previous_Word(FORM *form)
163450276Speter{
163550276Speter  FIELD *field = form->current;
1636166124Srafan  FIELD_CELL *bp = Address_Of_Current_Position_In_Buffer(form);
1637166124Srafan  FIELD_CELL *s;
1638166124Srafan  FIELD_CELL *t;
1639166124Srafan  bool again = FALSE;
164050276Speter
1641166124Srafan  T((T_CALLED("IFN_Previous_Word(%p)"), form));
1642166124Srafan
164350276Speter  /* We really need access to the data, so we have to synchronize */
164450276Speter  Synchronize_Buffer(form);
164550276Speter
1646166124Srafan  s = After_End_Of_Data(field->buf, (int)(bp - field->buf));
164750276Speter  /* s points now right after the last non-blank in the buffer before bp.
164850276Speter     If bp was in a word, s equals bp. In this case we must find the last
164950276Speter     whitespace in the buffer before bp and repeat the game to really find
165050276Speter     the previous word! */
1651166124Srafan  if (s == bp)
165250276Speter    again = TRUE;
1653166124Srafan
165450276Speter  /* And next call now goes backward to look for the last whitespace
165550276Speter     before that, pointing right after this, so it points to the begin
1656166124Srafan     of the previous word.
1657166124Srafan   */
1658166124Srafan  t = After_Last_Whitespace_Character(field->buf, (int)(s - field->buf));
165950276Speter#if !FRIENDLY_PREV_NEXT_WORD
1660166124Srafan  if (s == t)
1661166124Srafan    returnCode(E_REQUEST_DENIED);
166250276Speter#endif
166350276Speter  if (again)
1664166124Srafan    {
1665166124Srafan      /* and do it again, replacing bp by t */
1666166124Srafan      s = After_End_Of_Data(field->buf, (int)(t - field->buf));
1667166124Srafan      t = After_Last_Whitespace_Character(field->buf, (int)(s - field->buf));
166850276Speter#if !FRIENDLY_PREV_NEXT_WORD
1669166124Srafan      if (s == t)
1670166124Srafan	returnCode(E_REQUEST_DENIED);
167150276Speter#endif
167250276Speter    }
1673166124Srafan  Adjust_Cursor_Position(form, t);
1674166124Srafan  returnCode(E_OK);
167550276Speter}
167650276Speter
167750276Speter/*---------------------------------------------------------------------------
1678166124Srafan|   Facility      :  libnform
167950276Speter|   Function      :  static int IFN_Beginning_Of_Field(FORM * form)
1680166124Srafan|
168150276Speter|   Description   :  Place the cursor at the first non-pad character in
1682166124Srafan|                    the field.
168350276Speter|
1684166124Srafan|   Return Values :  E_OK             - success
168550276Speter+--------------------------------------------------------------------------*/
1686166124Srafanstatic int
1687166124SrafanIFN_Beginning_Of_Field(FORM *form)
168850276Speter{
168950276Speter  FIELD *field = form->current;
169050276Speter
1691166124Srafan  T((T_CALLED("IFN_Beginning_Of_Field(%p)"), form));
169250276Speter  Synchronize_Buffer(form);
169350276Speter  Adjust_Cursor_Position(form,
1694166124Srafan			 Get_Start_Of_Data(field->buf, Buffer_Length(field)));
1695166124Srafan  returnCode(E_OK);
169650276Speter}
169750276Speter
169850276Speter/*---------------------------------------------------------------------------
1699166124Srafan|   Facility      :  libnform
170050276Speter|   Function      :  static int IFN_End_Of_Field(FORM * form)
1701166124Srafan|
170250276Speter|   Description   :  Place the cursor after the last non-pad character in
170350276Speter|                    the field. If the field occupies the last position in
1704166124Srafan|                    the buffer, the cursor is positioned on the last
170550276Speter|                    character.
170650276Speter|
170750276Speter|   Return Values :  E_OK              - success
170850276Speter+--------------------------------------------------------------------------*/
1709166124Srafanstatic int
1710166124SrafanIFN_End_Of_Field(FORM *form)
171150276Speter{
171250276Speter  FIELD *field = form->current;
1713166124Srafan  FIELD_CELL *pos;
171450276Speter
1715166124Srafan  T((T_CALLED("IFN_End_Of_Field(%p)"), form));
171650276Speter  Synchronize_Buffer(form);
1717166124Srafan  pos = After_End_Of_Data(field->buf, Buffer_Length(field));
1718166124Srafan  if (pos == (field->buf + Buffer_Length(field)))
171950276Speter    pos--;
1720166124Srafan  Adjust_Cursor_Position(form, pos);
1721166124Srafan  returnCode(E_OK);
172250276Speter}
172350276Speter
172450276Speter/*---------------------------------------------------------------------------
1725166124Srafan|   Facility      :  libnform
172650276Speter|   Function      :  static int IFN_Beginning_Of_Line(FORM * form)
1727166124Srafan|
172850276Speter|   Description   :  Place the cursor on the first non-pad character in
172950276Speter|                    the current line of the field.
173050276Speter|
173150276Speter|   Return Values :  E_OK         - success
173250276Speter+--------------------------------------------------------------------------*/
1733166124Srafanstatic int
1734166124SrafanIFN_Beginning_Of_Line(FORM *form)
173550276Speter{
173650276Speter  FIELD *field = form->current;
173750276Speter
1738166124Srafan  T((T_CALLED("IFN_Beginning_Of_Line(%p)"), form));
173950276Speter  Synchronize_Buffer(form);
174050276Speter  Adjust_Cursor_Position(form,
1741166124Srafan			 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1742166124Srafan					   field->dcols));
1743166124Srafan  returnCode(E_OK);
174450276Speter}
174550276Speter
174650276Speter/*---------------------------------------------------------------------------
1747166124Srafan|   Facility      :  libnform
174850276Speter|   Function      :  static int IFN_End_Of_Line(FORM * form)
1749166124Srafan|
175050276Speter|   Description   :  Place the cursor after the last non-pad character in the
1751166124Srafan|                    current line of the field. If the field occupies the
175250276Speter|                    last column in the line, the cursor is positioned on the
175350276Speter|                    last character of the line.
175450276Speter|
175550276Speter|   Return Values :  E_OK        - success
175650276Speter+--------------------------------------------------------------------------*/
1757166124Srafanstatic int
1758166124SrafanIFN_End_Of_Line(FORM *form)
175950276Speter{
176050276Speter  FIELD *field = form->current;
1761166124Srafan  FIELD_CELL *pos;
1762166124Srafan  FIELD_CELL *bp;
176350276Speter
1764166124Srafan  T((T_CALLED("IFN_End_Of_Line(%p)"), form));
176550276Speter  Synchronize_Buffer(form);
1766166124Srafan  bp = Address_Of_Current_Row_In_Buffer(form);
1767166124Srafan  pos = After_End_Of_Data(bp, field->dcols);
176850276Speter  if (pos == (bp + field->dcols))
176950276Speter    pos--;
1770166124Srafan  Adjust_Cursor_Position(form, pos);
1771166124Srafan  returnCode(E_OK);
177250276Speter}
177350276Speter
177450276Speter/*---------------------------------------------------------------------------
1775166124Srafan|   Facility      :  libnform
177650276Speter|   Function      :  static int IFN_Left_Character(FORM * form)
1777166124Srafan|
177850276Speter|   Description   :  Move one character to the left in the current line.
1779166124Srafan|                    This doesn't cycle.
178050276Speter|
178150276Speter|   Return Values :  E_OK             - success
178250276Speter|                    E_REQUEST_DENIED - already in first column
178350276Speter+--------------------------------------------------------------------------*/
1784166124Srafanstatic int
1785166124SrafanIFN_Left_Character(FORM *form)
178650276Speter{
1787166124Srafan  int amount = myWCWIDTH(form->w, form->currow, form->curcol - 1);
1788166124Srafan  int oldcol = form->curcol;
1789166124Srafan
1790166124Srafan  T((T_CALLED("IFN_Left_Character(%p)"), form));
1791166124Srafan  if ((form->curcol -= amount) < 0)
179250276Speter    {
1793166124Srafan      form->curcol = oldcol;
1794166124Srafan      returnCode(E_REQUEST_DENIED);
179550276Speter    }
1796166124Srafan  returnCode(E_OK);
179750276Speter}
179850276Speter
179950276Speter/*---------------------------------------------------------------------------
1800166124Srafan|   Facility      :  libnform
180150276Speter|   Function      :  static int IFN_Right_Character(FORM * form)
1802166124Srafan|
180350276Speter|   Description   :  Move one character to the right in the current line.
180450276Speter|                    This doesn't cycle.
180550276Speter|
180650276Speter|   Return Values :  E_OK              - success
180750276Speter|                    E_REQUEST_DENIED  - already in last column
180850276Speter+--------------------------------------------------------------------------*/
1809166124Srafanstatic int
1810166124SrafanIFN_Right_Character(FORM *form)
181150276Speter{
1812166124Srafan  int amount = myWCWIDTH(form->w, form->currow, form->curcol);
1813166124Srafan  int oldcol = form->curcol;
1814166124Srafan
1815166124Srafan  T((T_CALLED("IFN_Right_Character(%p)"), form));
1816166124Srafan  if ((form->curcol += amount) >= form->current->dcols)
181750276Speter    {
181850276Speter#if GROW_IF_NAVIGATE
181950276Speter      FIELD *field = form->current;
1820166124Srafan
1821166124Srafan      if (Single_Line_Field(field) && Field_Grown(field, 1))
1822166124Srafan	returnCode(E_OK);
182350276Speter#endif
1824166124Srafan      form->curcol = oldcol;
1825166124Srafan      returnCode(E_REQUEST_DENIED);
182650276Speter    }
1827166124Srafan  returnCode(E_OK);
182850276Speter}
182950276Speter
183050276Speter/*---------------------------------------------------------------------------
1831166124Srafan|   Facility      :  libnform
183250276Speter|   Function      :  static int IFN_Up_Character(FORM * form)
1833166124Srafan|
183450276Speter|   Description   :  Move one line up. This doesn't cycle through the lines
183550276Speter|                    of the field.
183650276Speter|
183750276Speter|   Return Values :  E_OK              - success
183850276Speter|                    E_REQUEST_DENIED  - already in last column
183950276Speter+--------------------------------------------------------------------------*/
1840166124Srafanstatic int
1841166124SrafanIFN_Up_Character(FORM *form)
184250276Speter{
1843166124Srafan  T((T_CALLED("IFN_Up_Character(%p)"), form));
1844166124Srafan  if ((--(form->currow)) < 0)
184550276Speter    {
184650276Speter      form->currow++;
1847166124Srafan      returnCode(E_REQUEST_DENIED);
184850276Speter    }
1849166124Srafan  returnCode(E_OK);
185050276Speter}
185150276Speter
185250276Speter/*---------------------------------------------------------------------------
1853166124Srafan|   Facility      :  libnform
185450276Speter|   Function      :  static int IFN_Down_Character(FORM * form)
1855166124Srafan|
185650276Speter|   Description   :  Move one line down. This doesn't cycle through the
185750276Speter|                    lines of the field.
185850276Speter|
185950276Speter|   Return Values :  E_OK              - success
186050276Speter|                    E_REQUEST_DENIED  - already in last column
186150276Speter+--------------------------------------------------------------------------*/
1862166124Srafanstatic int
1863166124SrafanIFN_Down_Character(FORM *form)
186450276Speter{
186550276Speter  FIELD *field = form->current;
186650276Speter
1867166124Srafan  T((T_CALLED("IFN_Down_Character(%p)"), form));
1868166124Srafan  if ((++(form->currow)) == field->drows)
186950276Speter    {
187050276Speter#if GROW_IF_NAVIGATE
1871166124Srafan      if (!Single_Line_Field(field) && Field_Grown(field, 1))
1872166124Srafan	returnCode(E_OK);
187350276Speter#endif
187450276Speter      --(form->currow);
1875166124Srafan      returnCode(E_REQUEST_DENIED);
187650276Speter    }
1877166124Srafan  returnCode(E_OK);
187850276Speter}
187950276Speter/*----------------------------------------------------------------------------
1880166124Srafan  END of Intra-Field Navigation routines
188150276Speter  --------------------------------------------------------------------------*/
1882166124Srafan
188350276Speter/*----------------------------------------------------------------------------
188450276Speter  Vertical scrolling helper routines
188550276Speter  --------------------------------------------------------------------------*/
188650276Speter
188750276Speter/*---------------------------------------------------------------------------
1888166124Srafan|   Facility      :  libnform
1889166124Srafan|   Function      :  static int VSC_Generic(FORM *form, int nlines)
189050276Speter|
1891166124Srafan|   Description   :  Scroll multi-line field forward (nlines>0) or
1892166124Srafan|                    backward (nlines<0) this many lines.
189350276Speter|
1894166124Srafan|   Return Values :  E_OK              - success
189550276Speter|                    E_REQUEST_DENIED  - can't scroll
189650276Speter+--------------------------------------------------------------------------*/
1897166124Srafanstatic int
1898166124SrafanVSC_Generic(FORM *form, int nlines)
189950276Speter{
190050276Speter  FIELD *field = form->current;
190150276Speter  int res = E_REQUEST_DENIED;
1902166124Srafan  int rows_to_go = (nlines > 0 ? nlines : -nlines);
190350276Speter
1904166124Srafan  if (nlines > 0)
190550276Speter    {
1906166124Srafan      if ((rows_to_go + form->toprow) > (field->drows - field->rows))
190750276Speter	rows_to_go = (field->drows - field->rows - form->toprow);
190850276Speter
190950276Speter      if (rows_to_go > 0)
191050276Speter	{
191150276Speter	  form->currow += rows_to_go;
191250276Speter	  form->toprow += rows_to_go;
191350276Speter	  res = E_OK;
191450276Speter	}
191550276Speter    }
191650276Speter  else
191750276Speter    {
191850276Speter      if (rows_to_go > form->toprow)
191950276Speter	rows_to_go = form->toprow;
1920166124Srafan
192150276Speter      if (rows_to_go > 0)
192250276Speter	{
192350276Speter	  form->currow -= rows_to_go;
192450276Speter	  form->toprow -= rows_to_go;
192550276Speter	  res = E_OK;
192650276Speter	}
192750276Speter    }
1928166124Srafan  return (res);
192950276Speter}
193050276Speter/*----------------------------------------------------------------------------
193150276Speter  End of Vertical scrolling helper routines
193250276Speter  --------------------------------------------------------------------------*/
1933166124Srafan
193450276Speter/*----------------------------------------------------------------------------
193550276Speter  Vertical scrolling routines
193650276Speter  --------------------------------------------------------------------------*/
193750276Speter
193850276Speter/*---------------------------------------------------------------------------
1939166124Srafan|   Facility      :  libnform
194050276Speter|   Function      :  static int Vertical_Scrolling(
194150276Speter|                                           int (* const fct) (FORM *),
194250276Speter|                                           FORM * form)
1943166124Srafan|
1944166124Srafan|   Description   :  Performs the generic vertical scrolling routines.
194550276Speter|                    This has to check for a multi-line field and to set
1946166124Srafan|                    the _NEWTOP flag if scrolling really occurred.
194750276Speter|
194850276Speter|   Return Values :  Propagated error code from low-level driver calls
194950276Speter+--------------------------------------------------------------------------*/
1950166124Srafanstatic int
1951166124SrafanVertical_Scrolling(int (*const fct) (FORM *), FORM *form)
195250276Speter{
195350276Speter  int res = E_REQUEST_DENIED;
195450276Speter
195550276Speter  if (!Single_Line_Field(form->current))
195650276Speter    {
195750276Speter      res = fct(form);
195850276Speter      if (res == E_OK)
195950276Speter	form->current->status |= _NEWTOP;
196050276Speter    }
1961166124Srafan  return (res);
196250276Speter}
196350276Speter
196450276Speter/*---------------------------------------------------------------------------
1965166124Srafan|   Facility      :  libnform
196650276Speter|   Function      :  static int VSC_Scroll_Line_Forward(FORM * form)
1967166124Srafan|
196850276Speter|   Description   :  Scroll multi-line field forward a line
196950276Speter|
197050276Speter|   Return Values :  E_OK                - success
197150276Speter|                    E_REQUEST_DENIED    - no data ahead
197250276Speter+--------------------------------------------------------------------------*/
1973166124Srafanstatic int
1974166124SrafanVSC_Scroll_Line_Forward(FORM *form)
197550276Speter{
1976166124Srafan  T((T_CALLED("VSC_Scroll_Line_Forward(%p)"), form));
1977166124Srafan  returnCode(VSC_Generic(form, 1));
197850276Speter}
197950276Speter
198050276Speter/*---------------------------------------------------------------------------
1981166124Srafan|   Facility      :  libnform
198250276Speter|   Function      :  static int VSC_Scroll_Line_Backward(FORM * form)
1983166124Srafan|
198450276Speter|   Description   :  Scroll multi-line field backward a line
198550276Speter|
198650276Speter|   Return Values :  E_OK                - success
198750276Speter|                    E_REQUEST_DENIED    - no data behind
198850276Speter+--------------------------------------------------------------------------*/
1989166124Srafanstatic int
1990166124SrafanVSC_Scroll_Line_Backward(FORM *form)
199150276Speter{
1992166124Srafan  T((T_CALLED("VSC_Scroll_Line_Backward(%p)"), form));
1993166124Srafan  returnCode(VSC_Generic(form, -1));
199450276Speter}
199550276Speter
199650276Speter/*---------------------------------------------------------------------------
1997166124Srafan|   Facility      :  libnform
199850276Speter|   Function      :  static int VSC_Scroll_Page_Forward(FORM * form)
1999166124Srafan|
200050276Speter|   Description   :  Scroll a multi-line field forward a page
200150276Speter|
200250276Speter|   Return Values :  E_OK              - success
200350276Speter|                    E_REQUEST_DENIED  - no data ahead
200450276Speter+--------------------------------------------------------------------------*/
2005166124Srafanstatic int
2006166124SrafanVSC_Scroll_Page_Forward(FORM *form)
200750276Speter{
2008166124Srafan  T((T_CALLED("VSC_Scroll_Page_Forward(%p)"), form));
2009166124Srafan  returnCode(VSC_Generic(form, form->current->rows));
201050276Speter}
201150276Speter
201250276Speter/*---------------------------------------------------------------------------
2013166124Srafan|   Facility      :  libnform
201450276Speter|   Function      :  static int VSC_Scroll_Half_Page_Forward(FORM * form)
2015166124Srafan|
201650276Speter|   Description   :  Scroll a multi-line field forward half a page
201750276Speter|
201850276Speter|   Return Values :  E_OK              - success
201950276Speter|                    E_REQUEST_DENIED  - no data ahead
202050276Speter+--------------------------------------------------------------------------*/
2021166124Srafanstatic int
2022166124SrafanVSC_Scroll_Half_Page_Forward(FORM *form)
202350276Speter{
2024166124Srafan  T((T_CALLED("VSC_Scroll_Half_Page_Forward(%p)"), form));
2025166124Srafan  returnCode(VSC_Generic(form, (form->current->rows + 1) / 2));
202650276Speter}
202750276Speter
202850276Speter/*---------------------------------------------------------------------------
2029166124Srafan|   Facility      :  libnform
203050276Speter|   Function      :  static int VSC_Scroll_Page_Backward(FORM * form)
2031166124Srafan|
203250276Speter|   Description   :  Scroll a multi-line field backward a page
203350276Speter|
203450276Speter|   Return Values :  E_OK              - success
203550276Speter|                    E_REQUEST_DENIED  - no data behind
203650276Speter+--------------------------------------------------------------------------*/
2037166124Srafanstatic int
2038166124SrafanVSC_Scroll_Page_Backward(FORM *form)
203950276Speter{
2040166124Srafan  T((T_CALLED("VSC_Scroll_Page_Backward(%p)"), form));
2041166124Srafan  returnCode(VSC_Generic(form, -(form->current->rows)));
204250276Speter}
204350276Speter
204450276Speter/*---------------------------------------------------------------------------
2045166124Srafan|   Facility      :  libnform
204650276Speter|   Function      :  static int VSC_Scroll_Half_Page_Backward(FORM * form)
2047166124Srafan|
204850276Speter|   Description   :  Scroll a multi-line field backward half a page
204950276Speter|
205050276Speter|   Return Values :  E_OK              - success
205150276Speter|                    E_REQUEST_DENIED  - no data behind
205250276Speter+--------------------------------------------------------------------------*/
2053166124Srafanstatic int
2054166124SrafanVSC_Scroll_Half_Page_Backward(FORM *form)
205550276Speter{
2056166124Srafan  T((T_CALLED("VSC_Scroll_Half_Page_Backward(%p)"), form));
2057166124Srafan  returnCode(VSC_Generic(form, -((form->current->rows + 1) / 2)));
205850276Speter}
205950276Speter/*----------------------------------------------------------------------------
206050276Speter  End of Vertical scrolling routines
206150276Speter  --------------------------------------------------------------------------*/
2062166124Srafan
206350276Speter/*----------------------------------------------------------------------------
206450276Speter  Horizontal scrolling helper routines
206550276Speter  --------------------------------------------------------------------------*/
206650276Speter
206750276Speter/*---------------------------------------------------------------------------
2068166124Srafan|   Facility      :  libnform
2069166124Srafan|   Function      :  static int HSC_Generic(FORM *form, int ncolumns)
207050276Speter|
2071166124Srafan|   Description   :  Scroll single-line field forward (ncolumns>0) or
2072166124Srafan|                    backward (ncolumns<0) this many columns.
207350276Speter|
2074166124Srafan|   Return Values :  E_OK              - success
207550276Speter|                    E_REQUEST_DENIED  - can't scroll
207650276Speter+--------------------------------------------------------------------------*/
2077166124Srafanstatic int
2078166124SrafanHSC_Generic(FORM *form, int ncolumns)
207950276Speter{
208050276Speter  FIELD *field = form->current;
208150276Speter  int res = E_REQUEST_DENIED;
2082166124Srafan  int cols_to_go = (ncolumns > 0 ? ncolumns : -ncolumns);
208350276Speter
2084166124Srafan  if (ncolumns > 0)
208550276Speter    {
208650276Speter      if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
208750276Speter	cols_to_go = field->dcols - field->cols - form->begincol;
2088166124Srafan
208950276Speter      if (cols_to_go > 0)
209050276Speter	{
2091166124Srafan	  form->curcol += cols_to_go;
209250276Speter	  form->begincol += cols_to_go;
209350276Speter	  res = E_OK;
209450276Speter	}
209550276Speter    }
209650276Speter  else
209750276Speter    {
2098166124Srafan      if (cols_to_go > form->begincol)
209950276Speter	cols_to_go = form->begincol;
210050276Speter
210150276Speter      if (cols_to_go > 0)
210250276Speter	{
2103166124Srafan	  form->curcol -= cols_to_go;
210450276Speter	  form->begincol -= cols_to_go;
210550276Speter	  res = E_OK;
210650276Speter	}
210750276Speter    }
2108166124Srafan  return (res);
210950276Speter}
211050276Speter/*----------------------------------------------------------------------------
211150276Speter  End of Horizontal scrolling helper routines
211250276Speter  --------------------------------------------------------------------------*/
2113166124Srafan
211450276Speter/*----------------------------------------------------------------------------
211550276Speter  Horizontal scrolling routines
211650276Speter  --------------------------------------------------------------------------*/
211750276Speter
211850276Speter/*---------------------------------------------------------------------------
2119166124Srafan|   Facility      :  libnform
212050276Speter|   Function      :  static int Horizontal_Scrolling(
212150276Speter|                                          int (* const fct) (FORM *),
212250276Speter|                                          FORM * form)
2123166124Srafan|
2124166124Srafan|   Description   :  Performs the generic horizontal scrolling routines.
212550276Speter|                    This has to check for a single-line field.
212650276Speter|
212750276Speter|   Return Values :  Propagated error code from low-level driver calls
212850276Speter+--------------------------------------------------------------------------*/
2129166124Srafanstatic int
2130166124SrafanHorizontal_Scrolling(int (*const fct) (FORM *), FORM *form)
213150276Speter{
213250276Speter  if (Single_Line_Field(form->current))
213350276Speter    return fct(form);
213450276Speter  else
2135166124Srafan    return (E_REQUEST_DENIED);
213650276Speter}
213750276Speter
213850276Speter/*---------------------------------------------------------------------------
2139166124Srafan|   Facility      :  libnform
214050276Speter|   Function      :  static int HSC_Scroll_Char_Forward(FORM * form)
2141166124Srafan|
214250276Speter|   Description   :  Scroll single-line field forward a character
214350276Speter|
214450276Speter|   Return Values :  E_OK                - success
214550276Speter|                    E_REQUEST_DENIED    - no data ahead
214650276Speter+--------------------------------------------------------------------------*/
2147166124Srafanstatic int
2148166124SrafanHSC_Scroll_Char_Forward(FORM *form)
214950276Speter{
2150166124Srafan  T((T_CALLED("HSC_Scroll_Char_Forward(%p)"), form));
2151166124Srafan  returnCode(HSC_Generic(form, 1));
215250276Speter}
215350276Speter
215450276Speter/*---------------------------------------------------------------------------
2155166124Srafan|   Facility      :  libnform
215650276Speter|   Function      :  static int HSC_Scroll_Char_Backward(FORM * form)
2157166124Srafan|
215850276Speter|   Description   :  Scroll single-line field backward a character
215950276Speter|
216050276Speter|   Return Values :  E_OK                - success
216150276Speter|                    E_REQUEST_DENIED    - no data behind
216250276Speter+--------------------------------------------------------------------------*/
2163166124Srafanstatic int
2164166124SrafanHSC_Scroll_Char_Backward(FORM *form)
216550276Speter{
2166166124Srafan  T((T_CALLED("HSC_Scroll_Char_Backward(%p)"), form));
2167166124Srafan  returnCode(HSC_Generic(form, -1));
216850276Speter}
216950276Speter
217050276Speter/*---------------------------------------------------------------------------
2171166124Srafan|   Facility      :  libnform
217250276Speter|   Function      :  static int HSC_Horizontal_Line_Forward(FORM* form)
2173166124Srafan|
217450276Speter|   Description   :  Scroll single-line field forward a line
217550276Speter|
217650276Speter|   Return Values :  E_OK                - success
217750276Speter|                    E_REQUEST_DENIED    - no data ahead
217850276Speter+--------------------------------------------------------------------------*/
2179166124Srafanstatic int
2180166124SrafanHSC_Horizontal_Line_Forward(FORM *form)
218150276Speter{
2182166124Srafan  T((T_CALLED("HSC_Horizontal_Line_Forward(%p)"), form));
2183166124Srafan  returnCode(HSC_Generic(form, form->current->cols));
218450276Speter}
218550276Speter
218650276Speter/*---------------------------------------------------------------------------
2187166124Srafan|   Facility      :  libnform
218850276Speter|   Function      :  static int HSC_Horizontal_Half_Line_Forward(FORM* form)
2189166124Srafan|
219050276Speter|   Description   :  Scroll single-line field forward half a line
219150276Speter|
219250276Speter|   Return Values :  E_OK               - success
219350276Speter|                    E_REQUEST_DENIED   - no data ahead
219450276Speter+--------------------------------------------------------------------------*/
2195166124Srafanstatic int
2196166124SrafanHSC_Horizontal_Half_Line_Forward(FORM *form)
219750276Speter{
2198166124Srafan  T((T_CALLED("HSC_Horizontal_Half_Line_Forward(%p)"), form));
2199166124Srafan  returnCode(HSC_Generic(form, (form->current->cols + 1) / 2));
220050276Speter}
220150276Speter
220250276Speter/*---------------------------------------------------------------------------
2203166124Srafan|   Facility      :  libnform
220450276Speter|   Function      :  static int HSC_Horizontal_Line_Backward(FORM* form)
2205166124Srafan|
220650276Speter|   Description   :  Scroll single-line field backward a line
220750276Speter|
220850276Speter|   Return Values :  E_OK                - success
220950276Speter|                    E_REQUEST_DENIED    - no data behind
221050276Speter+--------------------------------------------------------------------------*/
2211166124Srafanstatic int
2212166124SrafanHSC_Horizontal_Line_Backward(FORM *form)
221350276Speter{
2214166124Srafan  T((T_CALLED("HSC_Horizontal_Line_Backward(%p)"), form));
2215166124Srafan  returnCode(HSC_Generic(form, -(form->current->cols)));
221650276Speter}
221750276Speter
221850276Speter/*---------------------------------------------------------------------------
2219166124Srafan|   Facility      :  libnform
222050276Speter|   Function      :  static int HSC_Horizontal_Half_Line_Backward(FORM* form)
2221166124Srafan|
222250276Speter|   Description   :  Scroll single-line field backward half a line
222350276Speter|
222450276Speter|   Return Values :  E_OK                - success
222550276Speter|                    E_REQUEST_DENIED    - no data behind
222650276Speter+--------------------------------------------------------------------------*/
2227166124Srafanstatic int
2228166124SrafanHSC_Horizontal_Half_Line_Backward(FORM *form)
222950276Speter{
2230166124Srafan  T((T_CALLED("HSC_Horizontal_Half_Line_Backward(%p)"), form));
2231166124Srafan  returnCode(HSC_Generic(form, -((form->current->cols + 1) / 2)));
223250276Speter}
223350276Speter
223450276Speter/*----------------------------------------------------------------------------
223550276Speter  End of Horizontal scrolling routines
223650276Speter  --------------------------------------------------------------------------*/
2237166124Srafan
223850276Speter/*----------------------------------------------------------------------------
223950276Speter  Helper routines for Field Editing
224050276Speter  --------------------------------------------------------------------------*/
224150276Speter
224250276Speter/*---------------------------------------------------------------------------
2243166124Srafan|   Facility      :  libnform
224450276Speter|   Function      :  static bool Is_There_Room_For_A_Line(FORM * form)
2245166124Srafan|
224650276Speter|   Description   :  Check whether or not there is enough room in the
224750276Speter|                    buffer to enter a whole line.
224850276Speter|
224950276Speter|   Return Values :  TRUE   - there is enough space
225050276Speter|                    FALSE  - there is not enough space
225150276Speter+--------------------------------------------------------------------------*/
2252166124SrafanNCURSES_INLINE static bool
2253166124SrafanIs_There_Room_For_A_Line(FORM *form)
225450276Speter{
225550276Speter  FIELD *field = form->current;
2256166124Srafan  FIELD_CELL *begin_of_last_line, *s;
2257166124Srafan
225850276Speter  Synchronize_Buffer(form);
2259166124Srafan  begin_of_last_line = Address_Of_Row_In_Buffer(field, (field->drows - 1));
2260166124Srafan  s = After_End_Of_Data(begin_of_last_line, field->dcols);
2261166124Srafan  return ((s == begin_of_last_line) ? TRUE : FALSE);
226250276Speter}
226350276Speter
226450276Speter/*---------------------------------------------------------------------------
2265166124Srafan|   Facility      :  libnform
226650276Speter|   Function      :  static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
2267166124Srafan|
226850276Speter|   Description   :  Checks whether or not there is room for a new character
226950276Speter|                    in the current line.
227050276Speter|
227150276Speter|   Return Values :  TRUE    - there is room
227250276Speter|                    FALSE   - there is not enough room (line full)
227350276Speter+--------------------------------------------------------------------------*/
2274166124SrafanNCURSES_INLINE static bool
2275166124SrafanIs_There_Room_For_A_Char_In_Line(FORM *form)
227650276Speter{
227750276Speter  int last_char_in_line;
227850276Speter
2279166124Srafan  wmove(form->w, form->currow, form->current->dcols - 1);
2280166124Srafan  last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
2281166124Srafan  wmove(form->w, form->currow, form->curcol);
228250276Speter  return (((last_char_in_line == form->current->pad) ||
228350276Speter	   is_blank(last_char_in_line)) ? TRUE : FALSE);
228450276Speter}
228550276Speter
228650276Speter#define There_Is_No_Room_For_A_Char_In_Line(f) \
228750276Speter  !Is_There_Room_For_A_Char_In_Line(f)
228850276Speter
228950276Speter/*---------------------------------------------------------------------------
2290166124Srafan|   Facility      :  libnform
229150276Speter|   Function      :  static int Insert_String(
229250276Speter|                                             FORM * form,
229350276Speter|                                             int row,
229450276Speter|                                             char *txt,
229550276Speter|                                             int  len )
2296166124Srafan|
229750276Speter|   Description   :  Insert the 'len' characters beginning at pointer 'txt'
229850276Speter|                    into the 'row' of the 'form'. The insertion occurs
229950276Speter|                    on the beginning of the row, all other characters are
2300166124Srafan|                    moved to the right. After the text a pad character will
230150276Speter|                    be inserted to separate the text from the rest. If
230250276Speter|                    necessary the insertion moves characters on the next
230350276Speter|                    line to make place for the requested insertion string.
230450276Speter|
2305166124Srafan|   Return Values :  E_OK              - success
230650276Speter|                    E_REQUEST_DENIED  -
230750276Speter|                    E_SYSTEM_ERROR    - system error
230850276Speter+--------------------------------------------------------------------------*/
2309166124Srafanstatic int
2310166124SrafanInsert_String(FORM *form, int row, FIELD_CELL *txt, int len)
2311166124Srafan{
2312166124Srafan  FIELD *field = form->current;
2313166124Srafan  FIELD_CELL *bp = Address_Of_Row_In_Buffer(field, row);
2314166124Srafan  int datalen = (int)(After_End_Of_Data(bp, field->dcols) - bp);
2315166124Srafan  int freelen = field->dcols - datalen;
2316166124Srafan  int requiredlen = len + 1;
2317166124Srafan  FIELD_CELL *split;
231850276Speter  int result = E_REQUEST_DENIED;
231950276Speter
232050276Speter  if (freelen >= requiredlen)
232150276Speter    {
2322166124Srafan      wmove(form->w, row, 0);
2323166124Srafan      myINSNSTR(form->w, txt, len);
2324166124Srafan      wmove(form->w, row, len);
2325166124Srafan      myINSNSTR(form->w, &myBLANK, 1);
232650276Speter      return E_OK;
232750276Speter    }
232850276Speter  else
2329166124Srafan    {
2330166124Srafan      /* we have to move characters on the next line. If we are on the
2331166124Srafan         last line this may work, if the field is growable */
233250276Speter      if ((row == (field->drows - 1)) && Growable(field))
233350276Speter	{
2334166124Srafan	  if (!Field_Grown(field, 1))
2335166124Srafan	    return (E_SYSTEM_ERROR);
233650276Speter	  /* !!!Side-Effect : might be changed due to growth!!! */
2337166124Srafan	  bp = Address_Of_Row_In_Buffer(field, row);
233850276Speter	}
233950276Speter
2340166124Srafan      if (row < (field->drows - 1))
2341166124Srafan	{
2342166124Srafan	  split =
2343166124Srafan	    After_Last_Whitespace_Character(bp,
2344166124Srafan					    (int)(Get_Start_Of_Data(bp
2345166124Srafan								    + field->dcols
2346166124Srafan								    - requiredlen,
2347166124Srafan								    requiredlen)
2348166124Srafan						  - bp));
234950276Speter	  /* split points now to the first character of the portion of the
235050276Speter	     line that must be moved to the next line */
2351166124Srafan	  datalen = (int)(split - bp);	/* + freelen has to stay on this line   */
2352166124Srafan	  freelen = field->dcols - (datalen + freelen);		/* for the next line */
235350276Speter
2354166124Srafan	  if ((result = Insert_String(form, row + 1, split, freelen)) == E_OK)
235550276Speter	    {
2356166124Srafan	      wmove(form->w, row, datalen);
235750276Speter	      wclrtoeol(form->w);
2358166124Srafan	      wmove(form->w, row, 0);
2359166124Srafan	      myINSNSTR(form->w, txt, len);
2360166124Srafan	      wmove(form->w, row, len);
2361166124Srafan	      myINSNSTR(form->w, &myBLANK, 1);
236250276Speter	      return E_OK;
236350276Speter	    }
236450276Speter	}
2365166124Srafan      return (result);
236650276Speter    }
236750276Speter}
236850276Speter
236950276Speter/*---------------------------------------------------------------------------
2370166124Srafan|   Facility      :  libnform
237150276Speter|   Function      :  static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
237250276Speter|                                             FORM * form)
2373166124Srafan|
237450276Speter|   Description   :  If a character has been entered into a field, it may
237550276Speter|                    be that wrapping has to occur. This routine checks
237650276Speter|                    whether or not wrapping is required and if so, performs
237750276Speter|                    the wrapping.
237850276Speter|
237950276Speter|   Return Values :  E_OK              - no wrapping required or wrapping
2380166124Srafan|                                        was successful
238150276Speter|                    E_REQUEST_DENIED  -
238250276Speter|                    E_SYSTEM_ERROR    - some system error
238350276Speter+--------------------------------------------------------------------------*/
2384166124Srafanstatic int
2385166124SrafanWrapping_Not_Necessary_Or_Wrapping_Ok(FORM *form)
238650276Speter{
2387166124Srafan  FIELD *field = form->current;
238850276Speter  int result = E_REQUEST_DENIED;
238950276Speter  bool Last_Row = ((field->drows - 1) == form->currow);
239050276Speter
2391166124Srafan  if ((field->opts & O_WRAP) &&	/* wrapping wanted     */
2392166124Srafan      (!Single_Line_Field(field)) &&	/* must be multi-line  */
2393166124Srafan      (There_Is_No_Room_For_A_Char_In_Line(form)) &&	/* line is full        */
2394166124Srafan      (!Last_Row || Growable(field)))	/* there are more lines */
239550276Speter    {
2396166124Srafan      FIELD_CELL *bp;
2397166124Srafan      FIELD_CELL *split;
239850276Speter      int chars_to_be_wrapped;
239950276Speter      int chars_to_remain_on_line;
2400166124Srafan
240150276Speter      if (Last_Row)
2402166124Srafan	{
2403166124Srafan	  /* the above logic already ensures, that in this case the field
240450276Speter	     is growable */
2405166124Srafan	  if (!Field_Grown(field, 1))
240650276Speter	    return E_SYSTEM_ERROR;
240750276Speter	}
240850276Speter      bp = Address_Of_Current_Row_In_Buffer(form);
2409166124Srafan      Window_To_Buffer(form->w, field);
2410166124Srafan      split = After_Last_Whitespace_Character(bp, field->dcols);
241150276Speter      /* split points to the first character of the sequence to be brought
241250276Speter         on the next line */
241350276Speter      chars_to_remain_on_line = (int)(split - bp);
2414166124Srafan      chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
241550276Speter      if (chars_to_remain_on_line > 0)
241650276Speter	{
2417166124Srafan	  if ((result = Insert_String(form, form->currow + 1, split,
2418166124Srafan				      chars_to_be_wrapped)) == E_OK)
241950276Speter	    {
2420166124Srafan	      wmove(form->w, form->currow, chars_to_remain_on_line);
242150276Speter	      wclrtoeol(form->w);
242250276Speter	      if (form->curcol >= chars_to_remain_on_line)
242350276Speter		{
242450276Speter		  form->currow++;
242550276Speter		  form->curcol -= chars_to_remain_on_line;
242650276Speter		}
242750276Speter	      return E_OK;
242850276Speter	    }
242950276Speter	}
243050276Speter      else
243150276Speter	return E_OK;
2432166124Srafan      if (result != E_OK)
243350276Speter	{
2434166124Srafan	  DeleteChar(form);
2435166124Srafan	  Window_To_Buffer(form->w, field);
243650276Speter	  result = E_REQUEST_DENIED;
243750276Speter	}
243850276Speter    }
243950276Speter  else
2440166124Srafan    result = E_OK;		/* wrapping was not necessary */
2441166124Srafan  return (result);
244250276Speter}
2443166124Srafan
244450276Speter/*----------------------------------------------------------------------------
244550276Speter  Field Editing routines
244650276Speter  --------------------------------------------------------------------------*/
244750276Speter
244850276Speter/*---------------------------------------------------------------------------
2449166124Srafan|   Facility      :  libnform
245050276Speter|   Function      :  static int Field_Editing(
245150276Speter|                                    int (* const fct) (FORM *),
245250276Speter|                                    FORM * form)
2453166124Srafan|
245450276Speter|   Description   :  Generic routine for field editing requests. The driver
245550276Speter|                    routines are only called for editable fields, the
2456166124Srafan|                    _WINDOW_MODIFIED flag is set if editing occurred.
245750276Speter|                    This is somewhat special due to the overload semantics
245850276Speter|                    of the NEW_LINE and DEL_PREV requests.
245950276Speter|
246050276Speter|   Return Values :  Error code from low level drivers.
246150276Speter+--------------------------------------------------------------------------*/
2462166124Srafanstatic int
2463166124SrafanField_Editing(int (*const fct) (FORM *), FORM *form)
246450276Speter{
246550276Speter  int res = E_REQUEST_DENIED;
246650276Speter
2467166124Srafan  /* We have to deal here with the specific case of the overloaded
2468166124Srafan     behavior of New_Line and Delete_Previous requests.
246950276Speter     They may end up in navigational requests if we are on the first
247050276Speter     character in a field. But navigation is also allowed on non-
247150276Speter     editable fields.
2472166124Srafan   */
2473166124Srafan  if ((fct == FE_Delete_Previous) &&
2474166124Srafan      (form->opts & O_BS_OVERLOAD) &&
2475166124Srafan      First_Position_In_Current_Field(form))
247650276Speter    {
2477166124Srafan      res = Inter_Field_Navigation(FN_Previous_Field, form);
247850276Speter    }
247950276Speter  else
248050276Speter    {
2481166124Srafan      if (fct == FE_New_Line)
248250276Speter	{
2483166124Srafan	  if ((form->opts & O_NL_OVERLOAD) &&
248450276Speter	      First_Position_In_Current_Field(form))
248550276Speter	    {
2486166124Srafan	      res = Inter_Field_Navigation(FN_Next_Field, form);
248750276Speter	    }
248850276Speter	  else
248950276Speter	    /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
249050276Speter	    res = fct(form);
249150276Speter	}
249250276Speter      else
249350276Speter	{
249450276Speter	  /* From now on, everything must be editable */
249550276Speter	  if (form->current->opts & O_EDIT)
249650276Speter	    {
249750276Speter	      res = fct(form);
2498166124Srafan	      if (res == E_OK)
249950276Speter		form->status |= _WINDOW_MODIFIED;
250050276Speter	    }
250150276Speter	}
250250276Speter    }
250350276Speter  return res;
250450276Speter}
250550276Speter
250650276Speter/*---------------------------------------------------------------------------
2507166124Srafan|   Facility      :  libnform
250850276Speter|   Function      :  static int FE_New_Line(FORM * form)
2509166124Srafan|
251050276Speter|   Description   :  Perform a new line request. This is rather complex
2511166124Srafan|                    compared to other routines in this code due to the
251250276Speter|                    rather difficult to understand description in the
251350276Speter|                    manuals.
251450276Speter|
251550276Speter|   Return Values :  E_OK               - success
251650276Speter|                    E_REQUEST_DENIED   - new line not allowed
251750276Speter|                    E_SYSTEM_ERROR     - system error
251850276Speter+--------------------------------------------------------------------------*/
2519166124Srafanstatic int
2520166124SrafanFE_New_Line(FORM *form)
252150276Speter{
2522166124Srafan  FIELD *field = form->current;
2523166124Srafan  FIELD_CELL *bp, *t;
2524166124Srafan  bool Last_Row = ((field->drows - 1) == form->currow);
2525166124Srafan
2526166124Srafan  T((T_CALLED("FE_New_Line(%p)"), form));
2527166124Srafan  if (form->status & _OVLMODE)
252850276Speter    {
2529166124Srafan      if (Last_Row &&
253050276Speter	  (!(Growable(field) && !Single_Line_Field(field))))
253150276Speter	{
253250276Speter	  if (!(form->opts & O_NL_OVERLOAD))
2533166124Srafan	    returnCode(E_REQUEST_DENIED);
2534166124Srafan	  wmove(form->w, form->currow, form->curcol);
253550276Speter	  wclrtoeol(form->w);
253650276Speter	  /* we have to set this here, although it is also
253750276Speter	     handled in the generic routine. The reason is,
253850276Speter	     that FN_Next_Field may fail, but the form is
253950276Speter	     definitively changed */
254050276Speter	  form->status |= _WINDOW_MODIFIED;
2541166124Srafan	  returnCode(Inter_Field_Navigation(FN_Next_Field, form));
254250276Speter	}
2543166124Srafan      else
254450276Speter	{
2545166124Srafan	  if (Last_Row && !Field_Grown(field, 1))
2546166124Srafan	    {
2547166124Srafan	      /* N.B.: due to the logic in the 'if', LastRow==TRUE
2548166124Srafan	         means here that the field is growable and not
2549166124Srafan	         a single-line field */
2550166124Srafan	      returnCode(E_SYSTEM_ERROR);
255150276Speter	    }
2552166124Srafan	  wmove(form->w, form->currow, form->curcol);
255350276Speter	  wclrtoeol(form->w);
255450276Speter	  form->currow++;
255550276Speter	  form->curcol = 0;
255650276Speter	  form->status |= _WINDOW_MODIFIED;
2557166124Srafan	  returnCode(E_OK);
255850276Speter	}
255950276Speter    }
2560166124Srafan  else
2561166124Srafan    {
2562166124Srafan      /* Insert Mode */
256350276Speter      if (Last_Row &&
256450276Speter	  !(Growable(field) && !Single_Line_Field(field)))
256550276Speter	{
256650276Speter	  if (!(form->opts & O_NL_OVERLOAD))
2567166124Srafan	    returnCode(E_REQUEST_DENIED);
2568166124Srafan	  returnCode(Inter_Field_Navigation(FN_Next_Field, form));
256950276Speter	}
2570166124Srafan      else
257150276Speter	{
257250276Speter	  bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2573166124Srafan
257450276Speter	  if (!(May_Do_It || Growable(field)))
2575166124Srafan	    returnCode(E_REQUEST_DENIED);
2576166124Srafan	  if (!May_Do_It && !Field_Grown(field, 1))
2577166124Srafan	    returnCode(E_SYSTEM_ERROR);
2578166124Srafan
2579166124Srafan	  bp = Address_Of_Current_Position_In_Buffer(form);
2580166124Srafan	  t = After_End_Of_Data(bp, field->dcols - form->curcol);
2581166124Srafan	  wmove(form->w, form->currow, form->curcol);
258250276Speter	  wclrtoeol(form->w);
258350276Speter	  form->currow++;
2584166124Srafan	  form->curcol = 0;
2585166124Srafan	  wmove(form->w, form->currow, form->curcol);
258650276Speter	  winsertln(form->w);
2587166124Srafan	  myADDNSTR(form->w, bp, (int)(t - bp));
258850276Speter	  form->status |= _WINDOW_MODIFIED;
2589166124Srafan	  returnCode(E_OK);
259050276Speter	}
259150276Speter    }
259250276Speter}
259350276Speter
259450276Speter/*---------------------------------------------------------------------------
2595166124Srafan|   Facility      :  libnform
259650276Speter|   Function      :  static int FE_Insert_Character(FORM * form)
2597166124Srafan|
259850276Speter|   Description   :  Insert blank character at the cursor position
259950276Speter|
260050276Speter|   Return Values :  E_OK
260150276Speter|                    E_REQUEST_DENIED
260250276Speter+--------------------------------------------------------------------------*/
2603166124Srafanstatic int
2604166124SrafanFE_Insert_Character(FORM *form)
260550276Speter{
260650276Speter  FIELD *field = form->current;
260750276Speter  int result = E_REQUEST_DENIED;
260850276Speter
2609166124Srafan  T((T_CALLED("FE_Insert_Character(%p)"), form));
2610166124Srafan  if (Check_Char(field->type, (int)C_BLANK, (TypeArgument *)(field->arg)))
261150276Speter    {
261250276Speter      bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
261350276Speter
261450276Speter      if (There_Is_Room ||
261550276Speter	  ((Single_Line_Field(field) && Growable(field))))
261650276Speter	{
2617166124Srafan	  if (!There_Is_Room && !Field_Grown(field, 1))
2618166124Srafan	    result = E_SYSTEM_ERROR;
261950276Speter	  else
262050276Speter	    {
2621166124Srafan	      winsch(form->w, (chtype)C_BLANK);
262250276Speter	      result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
262350276Speter	    }
262450276Speter	}
262550276Speter    }
2626166124Srafan  returnCode(result);
262750276Speter}
262850276Speter
262950276Speter/*---------------------------------------------------------------------------
2630166124Srafan|   Facility      :  libnform
263150276Speter|   Function      :  static int FE_Insert_Line(FORM * form)
2632166124Srafan|
263350276Speter|   Description   :  Insert a blank line at the cursor position
263450276Speter|
263550276Speter|   Return Values :  E_OK               - success
263650276Speter|                    E_REQUEST_DENIED   - line can not be inserted
263750276Speter+--------------------------------------------------------------------------*/
2638166124Srafanstatic int
2639166124SrafanFE_Insert_Line(FORM *form)
264050276Speter{
264150276Speter  FIELD *field = form->current;
264250276Speter  int result = E_REQUEST_DENIED;
264350276Speter
2644166124Srafan  T((T_CALLED("FE_Insert_Line(%p)"), form));
2645166124Srafan  if (Check_Char(field->type, (int)C_BLANK, (TypeArgument *)(field->arg)))
264650276Speter    {
2647166124Srafan      bool Maybe_Done = (form->currow != (field->drows - 1)) &&
2648166124Srafan      Is_There_Room_For_A_Line(form);
264950276Speter
265050276Speter      if (!Single_Line_Field(field) &&
265150276Speter	  (Maybe_Done || Growable(field)))
265250276Speter	{
2653166124Srafan	  if (!Maybe_Done && !Field_Grown(field, 1))
265450276Speter	    result = E_SYSTEM_ERROR;
265550276Speter	  else
265650276Speter	    {
265750276Speter	      form->curcol = 0;
265850276Speter	      winsertln(form->w);
265950276Speter	      result = E_OK;
266050276Speter	    }
266150276Speter	}
266250276Speter    }
2663166124Srafan  returnCode(result);
266450276Speter}
266550276Speter
266650276Speter/*---------------------------------------------------------------------------
2667166124Srafan|   Facility      :  libnform
266850276Speter|   Function      :  static int FE_Delete_Character(FORM * form)
2669166124Srafan|
267050276Speter|   Description   :  Delete character at the cursor position
267150276Speter|
267250276Speter|   Return Values :  E_OK    - success
267350276Speter+--------------------------------------------------------------------------*/
2674166124Srafanstatic int
2675166124SrafanFE_Delete_Character(FORM *form)
267650276Speter{
2677166124Srafan  T((T_CALLED("FE_Delete_Character(%p)"), form));
2678166124Srafan  DeleteChar(form);
2679166124Srafan  returnCode(E_OK);
268050276Speter}
268150276Speter
268250276Speter/*---------------------------------------------------------------------------
2683166124Srafan|   Facility      :  libnform
268450276Speter|   Function      :  static int FE_Delete_Previous(FORM * form)
2685166124Srafan|
268650276Speter|   Description   :  Delete character before cursor. Again this is a rather
268750276Speter|                    difficult piece compared to others due to the overloading
268850276Speter|                    semantics of backspace.
268950276Speter|                    N.B.: The case of overloaded BS on first field position
269050276Speter|                          is already handled in the generic routine.
269150276Speter|
269250276Speter|   Return Values :  E_OK                - success
269350276Speter|                    E_REQUEST_DENIED    - Character can't be deleted
269450276Speter+--------------------------------------------------------------------------*/
2695166124Srafanstatic int
2696166124SrafanFE_Delete_Previous(FORM *form)
269750276Speter{
2698166124Srafan  FIELD *field = form->current;
2699166124Srafan
2700166124Srafan  T((T_CALLED("FE_Delete_Previous(%p)"), form));
270150276Speter  if (First_Position_In_Current_Field(form))
2702166124Srafan    returnCode(E_REQUEST_DENIED);
270350276Speter
2704166124Srafan  if ((--(form->curcol)) < 0)
270550276Speter    {
2706166124Srafan      FIELD_CELL *this_line, *prev_line, *prev_end, *this_end;
2707166124Srafan      int this_row = form->currow;
2708166124Srafan
270950276Speter      form->curcol++;
2710166124Srafan      if (form->status & _OVLMODE)
2711166124Srafan	returnCode(E_REQUEST_DENIED);
2712166124Srafan
2713166124Srafan      prev_line = Address_Of_Row_In_Buffer(field, (form->currow - 1));
2714166124Srafan      this_line = Address_Of_Row_In_Buffer(field, (form->currow));
271550276Speter      Synchronize_Buffer(form);
2716166124Srafan      prev_end = After_End_Of_Data(prev_line, field->dcols);
2717166124Srafan      this_end = After_End_Of_Data(this_line, field->dcols);
2718166124Srafan      if ((int)(this_end - this_line) >
2719166124Srafan	  (field->cols - (int)(prev_end - prev_line)))
2720166124Srafan	returnCode(E_REQUEST_DENIED);
2721166124Srafan      wmove(form->w, form->currow, form->curcol);
272250276Speter      wdeleteln(form->w);
2723166124Srafan      Adjust_Cursor_Position(form, prev_end);
2724166124Srafan      /*
2725166124Srafan       * If we did not really move to the previous line, help the user a
2726166124Srafan       * little.  It is however a little inconsistent.  Normally, when
2727166124Srafan       * backspacing around the point where text wraps to a new line in a
2728166124Srafan       * multi-line form, we absorb one keystroke for the wrapping point.  That
2729166124Srafan       * is consistent with SVr4 forms.  However, SVr4 does not allow typing
2730166124Srafan       * into the last column of the field, and requires the user to enter a
2731166124Srafan       * newline to move to the next line.  Therefore it can consistently eat
2732166124Srafan       * that keystroke.  Since ncurses allows the last column, it wraps
2733166124Srafan       * automatically (given the proper options).  But we cannot eat the
2734166124Srafan       * keystroke to back over the wrapping point, since that would put the
2735166124Srafan       * cursor past the end of the form field.  In this case, just delete the
2736166124Srafan       * character at the end of the field.
2737166124Srafan       */
2738166124Srafan      if (form->currow == this_row && this_row > 0)
2739166124Srafan	{
2740166124Srafan	  form->currow -= 1;
2741166124Srafan	  form->curcol = field->dcols - 1;
2742166124Srafan	  DeleteChar(form);
2743166124Srafan	}
2744166124Srafan      else
2745166124Srafan	{
2746166124Srafan	  wmove(form->w, form->currow, form->curcol);
2747166124Srafan	  myADDNSTR(form->w, this_line, (int)(this_end - this_line));
2748166124Srafan	}
2749166124Srafan    }
2750166124Srafan  else
275150276Speter    {
2752166124Srafan      DeleteChar(form);
275350276Speter    }
2754166124Srafan  returnCode(E_OK);
275550276Speter}
275650276Speter
275750276Speter/*---------------------------------------------------------------------------
2758166124Srafan|   Facility      :  libnform
275950276Speter|   Function      :  static int FE_Delete_Line(FORM * form)
2760166124Srafan|
276150276Speter|   Description   :  Delete line at cursor position.
276250276Speter|
276350276Speter|   Return Values :  E_OK  - success
276450276Speter+--------------------------------------------------------------------------*/
2765166124Srafanstatic int
2766166124SrafanFE_Delete_Line(FORM *form)
276750276Speter{
2768166124Srafan  T((T_CALLED("FE_Delete_Line(%p)"), form));
276950276Speter  form->curcol = 0;
277050276Speter  wdeleteln(form->w);
2771166124Srafan  returnCode(E_OK);
277250276Speter}
277350276Speter
277450276Speter/*---------------------------------------------------------------------------
2775166124Srafan|   Facility      :  libnform
277650276Speter|   Function      :  static int FE_Delete_Word(FORM * form)
2777166124Srafan|
277850276Speter|   Description   :  Delete word at cursor position
277950276Speter|
278050276Speter|   Return Values :  E_OK               - success
278150276Speter|                    E_REQUEST_DENIED   - failure
278250276Speter+--------------------------------------------------------------------------*/
2783166124Srafanstatic int
2784166124SrafanFE_Delete_Word(FORM *form)
278550276Speter{
2786166124Srafan  FIELD *field = form->current;
2787166124Srafan  FIELD_CELL *bp = Address_Of_Current_Row_In_Buffer(form);
2788166124Srafan  FIELD_CELL *ep = bp + field->dcols;
2789166124Srafan  FIELD_CELL *cp = bp + form->curcol;
2790166124Srafan  FIELD_CELL *s;
2791166124Srafan
2792166124Srafan  T((T_CALLED("FE_Delete_Word(%p)"), form));
279350276Speter  Synchronize_Buffer(form);
2794166124Srafan  if (ISBLANK(*cp))
2795166124Srafan    returnCode(E_REQUEST_DENIED);	/* not in word */
279650276Speter
279750276Speter  /* move cursor to begin of word and erase to end of screen-line */
279850276Speter  Adjust_Cursor_Position(form,
2799166124Srafan			 After_Last_Whitespace_Character(bp, form->curcol));
2800166124Srafan  wmove(form->w, form->currow, form->curcol);
280150276Speter  wclrtoeol(form->w);
280250276Speter
280350276Speter  /* skip over word in buffer */
2804166124Srafan  s = Get_First_Whitespace_Character(cp, (int)(ep - cp));
280550276Speter  /* to begin of next word    */
2806166124Srafan  s = Get_Start_Of_Data(s, (int)(ep - s));
2807166124Srafan  if ((s != cp) && !ISBLANK(*s))
280850276Speter    {
280950276Speter      /* copy remaining line to window */
2810166124Srafan      myADDNSTR(form->w, s, (int)(s - After_End_Of_Data(s, (int)(ep - s))));
281150276Speter    }
2812166124Srafan  returnCode(E_OK);
281350276Speter}
281450276Speter
281550276Speter/*---------------------------------------------------------------------------
2816166124Srafan|   Facility      :  libnform
281750276Speter|   Function      :  static int FE_Clear_To_End_Of_Line(FORM * form)
2818166124Srafan|
281950276Speter|   Description   :  Clear to end of current line.
282050276Speter|
282150276Speter|   Return Values :  E_OK   - success
282250276Speter+--------------------------------------------------------------------------*/
2823166124Srafanstatic int
2824166124SrafanFE_Clear_To_End_Of_Line(FORM *form)
282550276Speter{
2826166124Srafan  T((T_CALLED("FE_Clear_To_End_Of_Line(%p)"), form));
2827166124Srafan  wmove(form->w, form->currow, form->curcol);
282850276Speter  wclrtoeol(form->w);
2829166124Srafan  returnCode(E_OK);
283050276Speter}
283150276Speter
283250276Speter/*---------------------------------------------------------------------------
2833166124Srafan|   Facility      :  libnform
2834166124Srafan|   Function      :  static int FE_Clear_To_End_Of_Field(FORM * form)
283550276Speter|
2836166124Srafan|   Description   :  Clear to end of field.
2837166124Srafan|
283850276Speter|   Return Values :  E_OK   - success
283950276Speter+--------------------------------------------------------------------------*/
2840166124Srafanstatic int
2841166124SrafanFE_Clear_To_End_Of_Field(FORM *form)
284250276Speter{
2843166124Srafan  T((T_CALLED("FE_Clear_To_End_Of_Field(%p)"), form));
2844166124Srafan  wmove(form->w, form->currow, form->curcol);
284550276Speter  wclrtobot(form->w);
2846166124Srafan  returnCode(E_OK);
284750276Speter}
284850276Speter
284950276Speter/*---------------------------------------------------------------------------
2850166124Srafan|   Facility      :  libnform
285150276Speter|   Function      :  static int FE_Clear_Field(FORM * form)
2852166124Srafan|
285350276Speter|   Description   :  Clear entire field.
285450276Speter|
285550276Speter|   Return Values :  E_OK   - success
285650276Speter+--------------------------------------------------------------------------*/
2857166124Srafanstatic int
2858166124SrafanFE_Clear_Field(FORM *form)
285950276Speter{
2860166124Srafan  T((T_CALLED("FE_Clear_Field(%p)"), form));
286150276Speter  form->currow = form->curcol = 0;
286250276Speter  werase(form->w);
2863166124Srafan  returnCode(E_OK);
286450276Speter}
286550276Speter/*----------------------------------------------------------------------------
2866166124Srafan  END of Field Editing routines
286750276Speter  --------------------------------------------------------------------------*/
2868166124Srafan
286950276Speter/*----------------------------------------------------------------------------
287050276Speter  Edit Mode routines
287150276Speter  --------------------------------------------------------------------------*/
287250276Speter
287350276Speter/*---------------------------------------------------------------------------
2874166124Srafan|   Facility      :  libnform
287550276Speter|   Function      :  static int EM_Overlay_Mode(FORM * form)
2876166124Srafan|
287750276Speter|   Description   :  Switch to overlay mode.
287850276Speter|
287950276Speter|   Return Values :  E_OK   - success
288050276Speter+--------------------------------------------------------------------------*/
2881166124Srafanstatic int
2882166124SrafanEM_Overlay_Mode(FORM *form)
288350276Speter{
2884166124Srafan  T((T_CALLED("EM_Overlay_Mode(%p)"), form));
288550276Speter  form->status |= _OVLMODE;
2886166124Srafan  returnCode(E_OK);
288750276Speter}
288850276Speter
288950276Speter/*---------------------------------------------------------------------------
2890166124Srafan|   Facility      :  libnform
289150276Speter|   Function      :  static int EM_Insert_Mode(FORM * form)
2892166124Srafan|
289350276Speter|   Description   :  Switch to insert mode
289450276Speter|
289550276Speter|   Return Values :  E_OK   - success
289650276Speter+--------------------------------------------------------------------------*/
2897166124Srafanstatic int
2898166124SrafanEM_Insert_Mode(FORM *form)
289950276Speter{
2900166124Srafan  T((T_CALLED("EM_Insert_Mode(%p)"), form));
290150276Speter  form->status &= ~_OVLMODE;
2902166124Srafan  returnCode(E_OK);
290350276Speter}
290450276Speter
290550276Speter/*----------------------------------------------------------------------------
2906166124Srafan  END of Edit Mode routines
290750276Speter  --------------------------------------------------------------------------*/
2908166124Srafan
290950276Speter/*----------------------------------------------------------------------------
291050276Speter  Helper routines for Choice Requests
291150276Speter  --------------------------------------------------------------------------*/
291250276Speter
291350276Speter/*---------------------------------------------------------------------------
2914166124Srafan|   Facility      :  libnform
291550276Speter|   Function      :  static bool Next_Choice(
291650276Speter|                                            FIELDTYPE * typ,
291750276Speter|                                            FIELD * field,
291850276Speter|                                            TypeArgument *argp)
2919166124Srafan|
292050276Speter|   Description   :  Get the next field choice. For linked types this is
292150276Speter|                    done recursively.
292250276Speter|
292350276Speter|   Return Values :  TRUE    - next choice successfully retrieved
292450276Speter|                    FALSE   - couldn't retrieve next choice
292550276Speter+--------------------------------------------------------------------------*/
2926166124Srafanstatic bool
2927166124SrafanNext_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
292850276Speter{
2929166124Srafan  if (!typ || !(typ->status & _HAS_CHOICE))
293050276Speter    return FALSE;
293150276Speter
293250276Speter  if (typ->status & _LINKED_TYPE)
293350276Speter    {
293450276Speter      assert(argp);
2935166124Srafan      return (
2936166124Srafan	       Next_Choice(typ->left, field, argp->left) ||
2937166124Srafan	       Next_Choice(typ->right, field, argp->right));
2938166124Srafan    }
293950276Speter  else
294050276Speter    {
294150276Speter      assert(typ->next);
2942166124Srafan      return typ->next(field, (void *)argp);
294350276Speter    }
294450276Speter}
294550276Speter
294650276Speter/*---------------------------------------------------------------------------
2947166124Srafan|   Facility      :  libnform
294850276Speter|   Function      :  static bool Previous_Choice(
294950276Speter|                                                FIELDTYPE * typ,
295050276Speter|                                                FIELD * field,
295150276Speter|                                                TypeArgument *argp)
2952166124Srafan|
295350276Speter|   Description   :  Get the previous field choice. For linked types this
295450276Speter|                    is done recursively.
295550276Speter|
295650276Speter|   Return Values :  TRUE    - previous choice successfully retrieved
295750276Speter|                    FALSE   - couldn't retrieve previous choice
295850276Speter+--------------------------------------------------------------------------*/
2959166124Srafanstatic bool
2960166124SrafanPrevious_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
296150276Speter{
2962166124Srafan  if (!typ || !(typ->status & _HAS_CHOICE))
296350276Speter    return FALSE;
296450276Speter
296550276Speter  if (typ->status & _LINKED_TYPE)
296650276Speter    {
296750276Speter      assert(argp);
2968166124Srafan      return (
2969166124Srafan	       Previous_Choice(typ->left, field, argp->left) ||
2970166124Srafan	       Previous_Choice(typ->right, field, argp->right));
2971166124Srafan    }
2972166124Srafan  else
297350276Speter    {
297450276Speter      assert(typ->prev);
2975166124Srafan      return typ->prev(field, (void *)argp);
297650276Speter    }
297750276Speter}
297850276Speter/*----------------------------------------------------------------------------
297950276Speter  End of Helper routines for Choice Requests
298050276Speter  --------------------------------------------------------------------------*/
2981166124Srafan
298250276Speter/*----------------------------------------------------------------------------
298350276Speter  Routines for Choice Requests
298450276Speter  --------------------------------------------------------------------------*/
298550276Speter
298650276Speter/*---------------------------------------------------------------------------
2987166124Srafan|   Facility      :  libnform
298850276Speter|   Function      :  static int CR_Next_Choice(FORM * form)
2989166124Srafan|
299050276Speter|   Description   :  Get the next field choice.
299150276Speter|
299250276Speter|   Return Values :  E_OK              - success
299350276Speter|                    E_REQUEST_DENIED  - next choice couldn't be retrieved
299450276Speter+--------------------------------------------------------------------------*/
2995166124Srafanstatic int
2996166124SrafanCR_Next_Choice(FORM *form)
299750276Speter{
299850276Speter  FIELD *field = form->current;
2999166124Srafan
3000166124Srafan  T((T_CALLED("CR_Next_Choice(%p)"), form));
300150276Speter  Synchronize_Buffer(form);
3002166124Srafan  returnCode((Next_Choice(field->type, field, (TypeArgument *)(field->arg)))
3003166124Srafan	     ? E_OK
3004166124Srafan	     : E_REQUEST_DENIED);
300550276Speter}
300650276Speter
300750276Speter/*---------------------------------------------------------------------------
3008166124Srafan|   Facility      :  libnform
300950276Speter|   Function      :  static int CR_Previous_Choice(FORM * form)
3010166124Srafan|
301150276Speter|   Description   :  Get the previous field choice.
301250276Speter|
301350276Speter|   Return Values :  E_OK              - success
301450276Speter|                    E_REQUEST_DENIED  - prev. choice couldn't be retrieved
301550276Speter+--------------------------------------------------------------------------*/
3016166124Srafanstatic int
3017166124SrafanCR_Previous_Choice(FORM *form)
301850276Speter{
301950276Speter  FIELD *field = form->current;
3020166124Srafan
3021166124Srafan  T((T_CALLED("CR_Previous_Choice(%p)"), form));
302250276Speter  Synchronize_Buffer(form);
3023166124Srafan  returnCode((Previous_Choice(field->type, field, (TypeArgument *)(field->arg)))
3024166124Srafan	     ? E_OK
3025166124Srafan	     : E_REQUEST_DENIED);
302650276Speter}
302750276Speter/*----------------------------------------------------------------------------
302850276Speter  End of Routines for Choice Requests
302950276Speter  --------------------------------------------------------------------------*/
3030166124Srafan
303150276Speter/*----------------------------------------------------------------------------
303250276Speter  Helper routines for Field Validations.
303350276Speter  --------------------------------------------------------------------------*/
303450276Speter
303550276Speter/*---------------------------------------------------------------------------
3036166124Srafan|   Facility      :  libnform
303750276Speter|   Function      :  static bool Check_Field(
303850276Speter|                                            FIELDTYPE * typ,
303950276Speter|                                            FIELD * field,
304050276Speter|                                            TypeArgument * argp)
3041166124Srafan|
304250276Speter|   Description   :  Check the field according to its fieldtype and its
304350276Speter|                    actual arguments. For linked fieldtypes this is done
304450276Speter|                    recursively.
304550276Speter|
304650276Speter|   Return Values :  TRUE       - field is valid
304750276Speter|                    FALSE      - field is invalid.
304850276Speter+--------------------------------------------------------------------------*/
3049166124Srafanstatic bool
3050166124SrafanCheck_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
305150276Speter{
305250276Speter  if (typ)
305350276Speter    {
305450276Speter      if (field->opts & O_NULLOK)
305550276Speter	{
3056166124Srafan	  FIELD_CELL *bp = field->buf;
3057166124Srafan
305850276Speter	  assert(bp);
3059166124Srafan	  while (ISBLANK(*bp))
3060166124Srafan	    {
3061166124Srafan	      bp++;
3062166124Srafan	    }
3063166124Srafan	  if (CharOf(*bp) == 0)
306450276Speter	    return TRUE;
306550276Speter	}
306650276Speter
306750276Speter      if (typ->status & _LINKED_TYPE)
306850276Speter	{
306950276Speter	  assert(argp);
3070166124Srafan	  return (
3071166124Srafan		   Check_Field(typ->left, field, argp->left) ||
3072166124Srafan		   Check_Field(typ->right, field, argp->right));
307350276Speter	}
3074166124Srafan      else
307550276Speter	{
307650276Speter	  if (typ->fcheck)
3077166124Srafan	    return typ->fcheck(field, (void *)argp);
307850276Speter	}
307950276Speter    }
308050276Speter  return TRUE;
308150276Speter}
308250276Speter
308350276Speter/*---------------------------------------------------------------------------
3084166124Srafan|   Facility      :  libnform
308550276Speter|   Function      :  bool _nc_Internal_Validation(FORM * form )
308650276Speter|
3087166124Srafan|   Description   :  Validate the current field of the form.
3088166124Srafan|
308950276Speter|   Return Values :  TRUE  - field is valid
309050276Speter|                    FALSE - field is invalid
309150276Speter+--------------------------------------------------------------------------*/
309276726SpeterNCURSES_EXPORT(bool)
3093166124Srafan_nc_Internal_Validation(FORM *form)
309450276Speter{
309550276Speter  FIELD *field;
309650276Speter
3097166124Srafan  field = form->current;
3098166124Srafan
309950276Speter  Synchronize_Buffer(form);
310050276Speter  if ((form->status & _FCHECK_REQUIRED) ||
310150276Speter      (!(field->opts & O_PASSOK)))
310250276Speter    {
3103166124Srafan      if (!Check_Field(field->type, field, (TypeArgument *)(field->arg)))
310450276Speter	return FALSE;
3105166124Srafan      form->status &= ~_FCHECK_REQUIRED;
310650276Speter      field->status |= _CHANGED;
310750276Speter      Synchronize_Linked_Fields(field);
310850276Speter    }
310950276Speter  return TRUE;
311050276Speter}
311150276Speter/*----------------------------------------------------------------------------
311250276Speter  End of Helper routines for Field Validations.
311350276Speter  --------------------------------------------------------------------------*/
3114166124Srafan
311550276Speter/*----------------------------------------------------------------------------
311650276Speter  Routines for Field Validation.
311750276Speter  --------------------------------------------------------------------------*/
311850276Speter
311950276Speter/*---------------------------------------------------------------------------
3120166124Srafan|   Facility      :  libnform
312150276Speter|   Function      :  static int FV_Validation(FORM * form)
3122166124Srafan|
312350276Speter|   Description   :  Validate the current field of the form.
312450276Speter|
312550276Speter|   Return Values :  E_OK             - field valid
312650276Speter|                    E_INVALID_FIELD  - field not valid
312750276Speter+--------------------------------------------------------------------------*/
3128166124Srafanstatic int
3129166124SrafanFV_Validation(FORM *form)
313050276Speter{
3131166124Srafan  T((T_CALLED("FV_Validation(%p)"), form));
313250276Speter  if (_nc_Internal_Validation(form))
3133166124Srafan    returnCode(E_OK);
313450276Speter  else
3135166124Srafan    returnCode(E_INVALID_FIELD);
313650276Speter}
313750276Speter/*----------------------------------------------------------------------------
313850276Speter  End of routines for Field Validation.
313950276Speter  --------------------------------------------------------------------------*/
3140166124Srafan
314150276Speter/*----------------------------------------------------------------------------
314250276Speter  Helper routines for Inter-Field Navigation
314350276Speter  --------------------------------------------------------------------------*/
314450276Speter
314550276Speter/*---------------------------------------------------------------------------
3146166124Srafan|   Facility      :  libnform
314750276Speter|   Function      :  static FIELD *Next_Field_On_Page(FIELD * field)
3148166124Srafan|
3149166124Srafan|   Description   :  Get the next field after the given field on the current
315050276Speter|                    page. The order of fields is the one defined by the
315150276Speter|                    fields array. Only visible and active fields are
315250276Speter|                    counted.
315350276Speter|
315450276Speter|   Return Values :  Pointer to the next field.
315550276Speter+--------------------------------------------------------------------------*/
3156166124SrafanNCURSES_INLINE static FIELD *
3157166124SrafanNext_Field_On_Page(FIELD *field)
315850276Speter{
3159166124Srafan  FORM *form = field->form;
316050276Speter  FIELD **field_on_page = &form->field[field->index];
316150276Speter  FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
3162166124Srafan  FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
316350276Speter
316450276Speter  do
316550276Speter    {
3166166124Srafan      field_on_page =
3167166124Srafan	(field_on_page == last_on_page) ? first_on_page : field_on_page + 1;
316850276Speter      if (Field_Is_Selectable(*field_on_page))
316950276Speter	break;
3170166124Srafan    }
3171166124Srafan  while (field != (*field_on_page));
3172166124Srafan  return (*field_on_page);
317350276Speter}
317450276Speter
317550276Speter/*---------------------------------------------------------------------------
3176166124Srafan|   Facility      :  libnform
317750276Speter|   Function      :  FIELD* _nc_First_Active_Field(FORM * form)
3178166124Srafan|
317950276Speter|   Description   :  Get the first active field on the current page,
318050276Speter|                    if there are such. If there are none, get the first
318150276Speter|                    visible field on the page. If there are also none,
318250276Speter|                    we return the first field on page and hope the best.
318350276Speter|
318450276Speter|   Return Values :  Pointer to calculated field.
318550276Speter+--------------------------------------------------------------------------*/
3186166124SrafanNCURSES_EXPORT(FIELD *)
3187166124Srafan_nc_First_Active_Field(FORM *form)
318850276Speter{
318950276Speter  FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
319050276Speter  FIELD *proposed = Next_Field_On_Page(*last_on_page);
319150276Speter
319250276Speter  if (proposed == *last_on_page)
3193166124Srafan    {
3194166124Srafan      /* there might be the special situation, where there is no
3195166124Srafan         active and visible field on the current page. We then select
3196166124Srafan         the first visible field on this readonly page
3197166124Srafan       */
319850276Speter      if (Field_Is_Not_Selectable(proposed))
319950276Speter	{
320050276Speter	  FIELD **field = &form->field[proposed->index];
320150276Speter	  FIELD **first = &form->field[form->page[form->curpage].pmin];
320250276Speter
320350276Speter	  do
320450276Speter	    {
3205166124Srafan	      field = (field == last_on_page) ? first : field + 1;
320650276Speter	      if (((*field)->opts & O_VISIBLE))
320750276Speter		break;
3208166124Srafan	    }
3209166124Srafan	  while (proposed != (*field));
3210166124Srafan
321150276Speter	  proposed = *field;
321250276Speter
3213166124Srafan	  if ((proposed == *last_on_page) && !(proposed->opts & O_VISIBLE))
3214166124Srafan	    {
3215166124Srafan	      /* This means, there is also no visible field on the page.
3216166124Srafan	         So we propose the first one and hope the very best...
3217166124Srafan	         Some very clever user has designed a readonly and invisible
3218166124Srafan	         page on this form.
321950276Speter	       */
322050276Speter	      proposed = *first;
322150276Speter	    }
322250276Speter	}
322350276Speter    }
3224166124Srafan  return (proposed);
322550276Speter}
322650276Speter
322750276Speter/*---------------------------------------------------------------------------
3228166124Srafan|   Facility      :  libnform
322950276Speter|   Function      :  static FIELD *Previous_Field_On_Page(FIELD * field)
3230166124Srafan|
3231166124Srafan|   Description   :  Get the previous field before the given field on the
3232166124Srafan|                    current page. The order of fields is the one defined by
323350276Speter|                    the fields array. Only visible and active fields are
323450276Speter|                    counted.
323550276Speter|
323650276Speter|   Return Values :  Pointer to the previous field.
323750276Speter+--------------------------------------------------------------------------*/
3238166124SrafanNCURSES_INLINE static FIELD *
3239166124SrafanPrevious_Field_On_Page(FIELD *field)
324050276Speter{
3241166124Srafan  FORM *form = field->form;
324250276Speter  FIELD **field_on_page = &form->field[field->index];
324350276Speter  FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
3244166124Srafan  FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
3245166124Srafan
324650276Speter  do
324750276Speter    {
3248166124Srafan      field_on_page =
3249166124Srafan	(field_on_page == first_on_page) ? last_on_page : field_on_page - 1;
325050276Speter      if (Field_Is_Selectable(*field_on_page))
325150276Speter	break;
3252166124Srafan    }
3253166124Srafan  while (field != (*field_on_page));
3254166124Srafan
325550276Speter  return (*field_on_page);
325650276Speter}
325750276Speter
325850276Speter/*---------------------------------------------------------------------------
3259166124Srafan|   Facility      :  libnform
326050276Speter|   Function      :  static FIELD *Sorted_Next_Field(FIELD * field)
3261166124Srafan|
3262166124Srafan|   Description   :  Get the next field after the given field on the current
326350276Speter|                    page. The order of fields is the one defined by the
326450276Speter|                    (row,column) geometry, rows are major.
326550276Speter|
326650276Speter|   Return Values :  Pointer to the next field.
326750276Speter+--------------------------------------------------------------------------*/
3268166124SrafanNCURSES_INLINE static FIELD *
3269166124SrafanSorted_Next_Field(FIELD *field)
327050276Speter{
327150276Speter  FIELD *field_on_page = field;
327250276Speter
327350276Speter  do
327450276Speter    {
327550276Speter      field_on_page = field_on_page->snext;
327650276Speter      if (Field_Is_Selectable(field_on_page))
327750276Speter	break;
3278166124Srafan    }
3279166124Srafan  while (field_on_page != field);
3280166124Srafan
328150276Speter  return (field_on_page);
328250276Speter}
328350276Speter
328450276Speter/*---------------------------------------------------------------------------
3285166124Srafan|   Facility      :  libnform
328650276Speter|   Function      :  static FIELD *Sorted_Previous_Field(FIELD * field)
3287166124Srafan|
3288166124Srafan|   Description   :  Get the previous field before the given field on the
3289166124Srafan|                    current page. The order of fields is the one defined
329050276Speter|                    by the (row,column) geometry, rows are major.
329150276Speter|
329250276Speter|   Return Values :  Pointer to the previous field.
329350276Speter+--------------------------------------------------------------------------*/
3294166124SrafanNCURSES_INLINE static FIELD *
3295166124SrafanSorted_Previous_Field(FIELD *field)
329650276Speter{
329750276Speter  FIELD *field_on_page = field;
329850276Speter
329950276Speter  do
330050276Speter    {
330150276Speter      field_on_page = field_on_page->sprev;
330250276Speter      if (Field_Is_Selectable(field_on_page))
330350276Speter	break;
3304166124Srafan    }
3305166124Srafan  while (field_on_page != field);
3306166124Srafan
330750276Speter  return (field_on_page);
330850276Speter}
330950276Speter
331050276Speter/*---------------------------------------------------------------------------
3311166124Srafan|   Facility      :  libnform
3312166124Srafan|   Function      :  static FIELD *Left_Neighbor_Field(FIELD * field)
3313166124Srafan|
3314166124Srafan|   Description   :  Get the left neighbor of the field on the same line
331550276Speter|                    and the same page. Cycles through the line.
331650276Speter|
3317166124Srafan|   Return Values :  Pointer to left neighbor field.
331850276Speter+--------------------------------------------------------------------------*/
3319166124SrafanNCURSES_INLINE static FIELD *
3320166124SrafanLeft_Neighbor_Field(FIELD *field)
332150276Speter{
332250276Speter  FIELD *field_on_page = field;
332350276Speter
3324166124Srafan  /* For a field that has really a left neighbor, the while clause
332550276Speter     immediately fails and the loop is left, positioned at the right
3326166124Srafan     neighbor. Otherwise we cycle backwards through the sorted field list
332750276Speter     until we enter the same line (from the right end).
3328166124Srafan   */
332950276Speter  do
333050276Speter    {
333150276Speter      field_on_page = Sorted_Previous_Field(field_on_page);
3332166124Srafan    }
3333166124Srafan  while (field_on_page->frow != field->frow);
3334166124Srafan
333550276Speter  return (field_on_page);
333650276Speter}
333750276Speter
333850276Speter/*---------------------------------------------------------------------------
3339166124Srafan|   Facility      :  libnform
3340166124Srafan|   Function      :  static FIELD *Right_Neighbor_Field(FIELD * field)
3341166124Srafan|
3342166124Srafan|   Description   :  Get the right neighbor of the field on the same line
334350276Speter|                    and the same page.
334450276Speter|
3345166124Srafan|   Return Values :  Pointer to right neighbor field.
334650276Speter+--------------------------------------------------------------------------*/
3347166124SrafanNCURSES_INLINE static FIELD *
3348166124SrafanRight_Neighbor_Field(FIELD *field)
334950276Speter{
335050276Speter  FIELD *field_on_page = field;
335150276Speter
3352166124Srafan  /* See the comments on Left_Neighbor_Field to understand how it works */
335350276Speter  do
335450276Speter    {
335550276Speter      field_on_page = Sorted_Next_Field(field_on_page);
3356166124Srafan    }
3357166124Srafan  while (field_on_page->frow != field->frow);
3358166124Srafan
335950276Speter  return (field_on_page);
336050276Speter}
336150276Speter
336250276Speter/*---------------------------------------------------------------------------
3363166124Srafan|   Facility      :  libnform
3364166124Srafan|   Function      :  static FIELD *Upper_Neighbor_Field(FIELD * field)
3365166124Srafan|
336650276Speter|   Description   :  Because of the row-major nature of sorting the fields,
3367166124Srafan|                    it is more difficult to define whats the upper neighbor
336850276Speter|                    field really means. We define that it must be on a
336950276Speter|                    'previous' line (cyclic order!) and is the rightmost
337050276Speter|                    field laying on the left side of the given field. If
337150276Speter|                    this set is empty, we take the first field on the line.
337250276Speter|
3373166124Srafan|   Return Values :  Pointer to the upper neighbor field.
337450276Speter+--------------------------------------------------------------------------*/
3375166124Srafanstatic FIELD *
3376166124SrafanUpper_Neighbor_Field(FIELD *field)
337750276Speter{
337850276Speter  FIELD *field_on_page = field;
337950276Speter  int frow = field->frow;
338050276Speter  int fcol = field->fcol;
338150276Speter
338250276Speter  /* Walk back to the 'previous' line. The second term in the while clause
338350276Speter     just guarantees that we stop if we cycled through the line because
338450276Speter     there might be no 'previous' line if the page has just one line.
3385166124Srafan   */
338650276Speter  do
338750276Speter    {
338850276Speter      field_on_page = Sorted_Previous_Field(field_on_page);
3389166124Srafan    }
3390166124Srafan  while (field_on_page->frow == frow && field_on_page->fcol != fcol);
3391166124Srafan
3392166124Srafan  if (field_on_page->frow != frow)
3393166124Srafan    {
3394166124Srafan      /* We really found a 'previous' line. We are positioned at the
339550276Speter         rightmost field on this line */
3396166124Srafan      frow = field_on_page->frow;
339750276Speter
3398166124Srafan      /* We walk to the left as long as we are really right of the
3399166124Srafan         field. */
3400166124Srafan      while (field_on_page->frow == frow && field_on_page->fcol > fcol)
340150276Speter	field_on_page = Sorted_Previous_Field(field_on_page);
340250276Speter
3403166124Srafan      /* If we wrapped, just go to the right which is the first field on
3404166124Srafan         the row */
3405166124Srafan      if (field_on_page->frow != frow)
340650276Speter	field_on_page = Sorted_Next_Field(field_on_page);
340750276Speter    }
3408166124Srafan
340950276Speter  return (field_on_page);
341050276Speter}
341150276Speter
341250276Speter/*---------------------------------------------------------------------------
3413166124Srafan|   Facility      :  libnform
3414166124Srafan|   Function      :  static FIELD *Down_Neighbor_Field(FIELD * field)
3415166124Srafan|
341650276Speter|   Description   :  Because of the row-major nature of sorting the fields,
3417166124Srafan|                    its more difficult to define whats the down neighbor
341850276Speter|                    field really means. We define that it must be on a
341950276Speter|                    'next' line (cyclic order!) and is the leftmost
342050276Speter|                    field laying on the right side of the given field. If
342150276Speter|                    this set is empty, we take the last field on the line.
342250276Speter|
3423166124Srafan|   Return Values :  Pointer to the upper neighbor field.
342450276Speter+--------------------------------------------------------------------------*/
3425166124Srafanstatic FIELD *
3426166124SrafanDown_Neighbor_Field(FIELD *field)
342750276Speter{
342850276Speter  FIELD *field_on_page = field;
342950276Speter  int frow = field->frow;
343050276Speter  int fcol = field->fcol;
343150276Speter
343250276Speter  /* Walk forward to the 'next' line. The second term in the while clause
343350276Speter     just guarantees that we stop if we cycled through the line because
343450276Speter     there might be no 'next' line if the page has just one line.
3435166124Srafan   */
343650276Speter  do
343750276Speter    {
343850276Speter      field_on_page = Sorted_Next_Field(field_on_page);
3439166124Srafan    }
3440166124Srafan  while (field_on_page->frow == frow && field_on_page->fcol != fcol);
344150276Speter
3442166124Srafan  if (field_on_page->frow != frow)
3443166124Srafan    {
3444166124Srafan      /* We really found a 'next' line. We are positioned at the rightmost
344550276Speter         field on this line */
344650276Speter      frow = field_on_page->frow;
344750276Speter
3448166124Srafan      /* We walk to the right as long as we are really left of the
3449166124Srafan         field. */
3450166124Srafan      while (field_on_page->frow == frow && field_on_page->fcol < fcol)
345150276Speter	field_on_page = Sorted_Next_Field(field_on_page);
345250276Speter
3453166124Srafan      /* If we wrapped, just go to the left which is the last field on
3454166124Srafan         the row */
3455166124Srafan      if (field_on_page->frow != frow)
345650276Speter	field_on_page = Sorted_Previous_Field(field_on_page);
345750276Speter    }
3458166124Srafan
3459166124Srafan  return (field_on_page);
346050276Speter}
3461166124Srafan
346250276Speter/*----------------------------------------------------------------------------
346350276Speter  Inter-Field Navigation routines
346450276Speter  --------------------------------------------------------------------------*/
346550276Speter
346650276Speter/*---------------------------------------------------------------------------
3467166124Srafan|   Facility      :  libnform
346850276Speter|   Function      :  static int Inter_Field_Navigation(
346950276Speter|                                           int (* const fct) (FORM *),
347050276Speter|                                           FORM * form)
3471166124Srafan|
3472166124Srafan|   Description   :  Generic behavior for changing the current field, the
347350276Speter|                    field is left and a new field is entered. So the field
347450276Speter|                    must be validated and the field init/term hooks must
347550276Speter|                    be called.
347650276Speter|
347750276Speter|   Return Values :  E_OK                - success
347850276Speter|                    E_INVALID_FIELD     - field is invalid
347950276Speter|                    some other          - error from subordinate call
348050276Speter+--------------------------------------------------------------------------*/
3481166124Srafanstatic int
3482166124SrafanInter_Field_Navigation(int (*const fct) (FORM *), FORM *form)
348350276Speter{
348450276Speter  int res;
348550276Speter
3486166124Srafan  if (!_nc_Internal_Validation(form))
348750276Speter    res = E_INVALID_FIELD;
348850276Speter  else
348950276Speter    {
3490166124Srafan      Call_Hook(form, fieldterm);
349150276Speter      res = fct(form);
3492166124Srafan      Call_Hook(form, fieldinit);
349350276Speter    }
349450276Speter  return res;
349550276Speter}
349650276Speter
349750276Speter/*---------------------------------------------------------------------------
3498166124Srafan|   Facility      :  libnform
349950276Speter|   Function      :  static int FN_Next_Field(FORM * form)
3500166124Srafan|
350150276Speter|   Description   :  Move to the next field on the current page of the form
350250276Speter|
350350276Speter|   Return Values :  E_OK                 - success
350450276Speter|                    != E_OK              - error from subordinate call
350550276Speter+--------------------------------------------------------------------------*/
3506166124Srafanstatic int
3507166124SrafanFN_Next_Field(FORM *form)
350850276Speter{
3509166124Srafan  T((T_CALLED("FN_Next_Field(%p)"), form));
3510166124Srafan  returnCode(_nc_Set_Current_Field(form,
3511166124Srafan				   Next_Field_On_Page(form->current)));
351250276Speter}
351350276Speter
351450276Speter/*---------------------------------------------------------------------------
3515166124Srafan|   Facility      :  libnform
351650276Speter|   Function      :  static int FN_Previous_Field(FORM * form)
3517166124Srafan|
3518166124Srafan|   Description   :  Move to the previous field on the current page of the
351950276Speter|                    form
352050276Speter|
352150276Speter|   Return Values :  E_OK                 - success
352250276Speter|                    != E_OK              - error from subordinate call
352350276Speter+--------------------------------------------------------------------------*/
3524166124Srafanstatic int
3525166124SrafanFN_Previous_Field(FORM *form)
352650276Speter{
3527166124Srafan  T((T_CALLED("FN_Previous_Field(%p)"), form));
3528166124Srafan  returnCode(_nc_Set_Current_Field(form,
3529166124Srafan				   Previous_Field_On_Page(form->current)));
353050276Speter}
353150276Speter
353250276Speter/*---------------------------------------------------------------------------
3533166124Srafan|   Facility      :  libnform
353450276Speter|   Function      :  static int FN_First_Field(FORM * form)
3535166124Srafan|
353650276Speter|   Description   :  Move to the first field on the current page of the form
353750276Speter|
353850276Speter|   Return Values :  E_OK                 - success
353950276Speter|                    != E_OK              - error from subordinate call
354050276Speter+--------------------------------------------------------------------------*/
3541166124Srafanstatic int
3542166124SrafanFN_First_Field(FORM *form)
354350276Speter{
3544166124Srafan  T((T_CALLED("FN_First_Field(%p)"), form));
3545166124Srafan  returnCode(_nc_Set_Current_Field(form,
3546166124Srafan				   Next_Field_On_Page(form->field[form->page[form->curpage].pmax])));
354750276Speter}
354850276Speter
354950276Speter/*---------------------------------------------------------------------------
3550166124Srafan|   Facility      :  libnform
355150276Speter|   Function      :  static int FN_Last_Field(FORM * form)
3552166124Srafan|
355350276Speter|   Description   :  Move to the last field on the current page of the form
355450276Speter|
355550276Speter|   Return Values :  E_OK                 - success
355650276Speter|                    != E_OK              - error from subordinate call
355750276Speter+--------------------------------------------------------------------------*/
3558166124Srafanstatic int
3559166124SrafanFN_Last_Field(FORM *form)
356050276Speter{
3561166124Srafan  T((T_CALLED("FN_Last_Field(%p)"), form));
3562166124Srafan  returnCode(
3563166124Srafan	      _nc_Set_Current_Field(form,
3564166124Srafan				    Previous_Field_On_Page(form->field[form->page[form->curpage].pmin])));
356550276Speter}
356650276Speter
356750276Speter/*---------------------------------------------------------------------------
3568166124Srafan|   Facility      :  libnform
356950276Speter|   Function      :  static int FN_Sorted_Next_Field(FORM * form)
3570166124Srafan|
357150276Speter|   Description   :  Move to the sorted next field on the current page
357250276Speter|                    of the form.
357350276Speter|
357450276Speter|   Return Values :  E_OK            - success
357550276Speter|                    != E_OK         - error from subordinate call
357650276Speter+--------------------------------------------------------------------------*/
3577166124Srafanstatic int
3578166124SrafanFN_Sorted_Next_Field(FORM *form)
357950276Speter{
3580166124Srafan  T((T_CALLED("FN_Sorted_Next_Field(%p)"), form));
3581166124Srafan  returnCode(_nc_Set_Current_Field(form,
3582166124Srafan				   Sorted_Next_Field(form->current)));
358350276Speter}
358450276Speter
358550276Speter/*---------------------------------------------------------------------------
3586166124Srafan|   Facility      :  libnform
358750276Speter|   Function      :  static int FN_Sorted_Previous_Field(FORM * form)
3588166124Srafan|
358950276Speter|   Description   :  Move to the sorted previous field on the current page
359050276Speter|                    of the form.
359150276Speter|
359250276Speter|   Return Values :  E_OK            - success
359350276Speter|                    != E_OK         - error from subordinate call
359450276Speter+--------------------------------------------------------------------------*/
3595166124Srafanstatic int
3596166124SrafanFN_Sorted_Previous_Field(FORM *form)
359750276Speter{
3598166124Srafan  T((T_CALLED("FN_Sorted_Previous_Field(%p)"), form));
3599166124Srafan  returnCode(_nc_Set_Current_Field(form,
3600166124Srafan				   Sorted_Previous_Field(form->current)));
360150276Speter}
360250276Speter
360350276Speter/*---------------------------------------------------------------------------
3604166124Srafan|   Facility      :  libnform
360550276Speter|   Function      :  static int FN_Sorted_First_Field(FORM * form)
3606166124Srafan|
360750276Speter|   Description   :  Move to the sorted first field on the current page
360850276Speter|                    of the form.
360950276Speter|
361050276Speter|   Return Values :  E_OK            - success
361150276Speter|                    != E_OK         - error from subordinate call
361250276Speter+--------------------------------------------------------------------------*/
3613166124Srafanstatic int
3614166124SrafanFN_Sorted_First_Field(FORM *form)
361550276Speter{
3616166124Srafan  T((T_CALLED("FN_Sorted_First_Field(%p)"), form));
3617166124Srafan  returnCode(_nc_Set_Current_Field(form,
3618166124Srafan				   Sorted_Next_Field(form->field[form->page[form->curpage].smax])));
361950276Speter}
362050276Speter
362150276Speter/*---------------------------------------------------------------------------
3622166124Srafan|   Facility      :  libnform
362350276Speter|   Function      :  static int FN_Sorted_Last_Field(FORM * form)
3624166124Srafan|
362550276Speter|   Description   :  Move to the sorted last field on the current page
362650276Speter|                    of the form.
362750276Speter|
362850276Speter|   Return Values :  E_OK            - success
362950276Speter|                    != E_OK         - error from subordinate call
363050276Speter+--------------------------------------------------------------------------*/
3631166124Srafanstatic int
3632166124SrafanFN_Sorted_Last_Field(FORM *form)
363350276Speter{
3634166124Srafan  T((T_CALLED("FN_Sorted_Last_Field(%p)"), form));
3635166124Srafan  returnCode(_nc_Set_Current_Field(form,
3636166124Srafan				   Sorted_Previous_Field(form->field[form->page[form->curpage].smin])));
363750276Speter}
363850276Speter
363950276Speter/*---------------------------------------------------------------------------
3640166124Srafan|   Facility      :  libnform
364150276Speter|   Function      :  static int FN_Left_Field(FORM * form)
3642166124Srafan|
364350276Speter|   Description   :  Get the field on the left of the current field on the
364450276Speter|                    same line and the same page. Cycles through the line.
364550276Speter|
364650276Speter|   Return Values :  E_OK            - success
364750276Speter|                    != E_OK         - error from subordinate call
364850276Speter+--------------------------------------------------------------------------*/
3649166124Srafanstatic int
3650166124SrafanFN_Left_Field(FORM *form)
365150276Speter{
3652166124Srafan  T((T_CALLED("FN_Left_Field(%p)"), form));
3653166124Srafan  returnCode(_nc_Set_Current_Field(form,
3654166124Srafan				   Left_Neighbor_Field(form->current)));
365550276Speter}
365650276Speter
365750276Speter/*---------------------------------------------------------------------------
3658166124Srafan|   Facility      :  libnform
365950276Speter|   Function      :  static int FN_Right_Field(FORM * form)
3660166124Srafan|
366150276Speter|   Description   :  Get the field on the right of the current field on the
366250276Speter|                    same line and the same page. Cycles through the line.
366350276Speter|
366450276Speter|   Return Values :  E_OK            - success
366550276Speter|                    != E_OK         - error from subordinate call
366650276Speter+--------------------------------------------------------------------------*/
3667166124Srafanstatic int
3668166124SrafanFN_Right_Field(FORM *form)
366950276Speter{
3670166124Srafan  T((T_CALLED("FN_Right_Field(%p)"), form));
3671166124Srafan  returnCode(_nc_Set_Current_Field(form,
3672166124Srafan				   Right_Neighbor_Field(form->current)));
367350276Speter}
367450276Speter
367550276Speter/*---------------------------------------------------------------------------
3676166124Srafan|   Facility      :  libnform
367750276Speter|   Function      :  static int FN_Up_Field(FORM * form)
3678166124Srafan|
3679166124Srafan|   Description   :  Get the upper neighbor of the current field. This
368050276Speter|                    cycles through the page. See the comments of the
3681166124Srafan|                    Upper_Neighbor_Field function to understand how
3682166124Srafan|                    'upper' is defined.
368350276Speter|
368450276Speter|   Return Values :  E_OK            - success
368550276Speter|                    != E_OK         - error from subordinate call
368650276Speter+--------------------------------------------------------------------------*/
3687166124Srafanstatic int
3688166124SrafanFN_Up_Field(FORM *form)
368950276Speter{
3690166124Srafan  T((T_CALLED("FN_Up_Field(%p)"), form));
3691166124Srafan  returnCode(_nc_Set_Current_Field(form,
3692166124Srafan				   Upper_Neighbor_Field(form->current)));
369350276Speter}
369450276Speter
369550276Speter/*---------------------------------------------------------------------------
3696166124Srafan|   Facility      :  libnform
369750276Speter|   Function      :  static int FN_Down_Field(FORM * form)
3698166124Srafan|
3699166124Srafan|   Description   :  Get the down neighbor of the current field. This
370050276Speter|                    cycles through the page. See the comments of the
3701166124Srafan|                    Down_Neighbor_Field function to understand how
3702166124Srafan|                    'down' is defined.
370350276Speter|
370450276Speter|   Return Values :  E_OK            - success
370550276Speter|                    != E_OK         - error from subordinate call
370650276Speter+--------------------------------------------------------------------------*/
3707166124Srafanstatic int
3708166124SrafanFN_Down_Field(FORM *form)
370950276Speter{
3710166124Srafan  T((T_CALLED("FN_Down_Field(%p)"), form));
3711166124Srafan  returnCode(_nc_Set_Current_Field(form,
3712166124Srafan				   Down_Neighbor_Field(form->current)));
371350276Speter}
371450276Speter/*----------------------------------------------------------------------------
3715166124Srafan  END of Field Navigation routines
371650276Speter  --------------------------------------------------------------------------*/
3717166124Srafan
371850276Speter/*----------------------------------------------------------------------------
371950276Speter  Helper routines for Page Navigation
372050276Speter  --------------------------------------------------------------------------*/
372150276Speter
372250276Speter/*---------------------------------------------------------------------------
3723166124Srafan|   Facility      :  libnform
372450276Speter|   Function      :  int _nc_Set_Form_Page(FORM * form,
372550276Speter|                                          int page,
372650276Speter|                                          FIELD * field)
3727166124Srafan|
3728166124Srafan|   Description   :  Make the given page number the current page and make
372950276Speter|                    the given field the current field on the page. If
373050276Speter|                    for the field NULL is given, make the first field on
373150276Speter|                    the page the current field. The routine acts only
373250276Speter|                    if the requested page is not the current page.
373350276Speter|
373450276Speter|   Return Values :  E_OK                - success
373550276Speter|                    != E_OK             - error from subordinate call
3736166124Srafan|                    E_BAD_ARGUMENT      - invalid field pointer
3737166124Srafan|                    E_SYSTEM_ERROR      - some severe basic error
373850276Speter+--------------------------------------------------------------------------*/
373976726SpeterNCURSES_EXPORT(int)
3740166124Srafan_nc_Set_Form_Page(FORM *form, int page, FIELD *field)
374150276Speter{
374250276Speter  int res = E_OK;
374350276Speter
3744166124Srafan  if ((form->curpage != page))
374550276Speter    {
374650276Speter      FIELD *last_field, *field_on_page;
374750276Speter
374850276Speter      werase(Get_Form_Window(form));
374950276Speter      form->curpage = page;
375050276Speter      last_field = field_on_page = form->field[form->page[page].smin];
375150276Speter      do
375250276Speter	{
375350276Speter	  if (field_on_page->opts & O_VISIBLE)
3754166124Srafan	    if ((res = Display_Field(field_on_page)) != E_OK)
3755166124Srafan	      return (res);
375650276Speter	  field_on_page = field_on_page->snext;
3757166124Srafan	}
3758166124Srafan      while (field_on_page != last_field);
375950276Speter
376050276Speter      if (field)
3761166124Srafan	res = _nc_Set_Current_Field(form, field);
376250276Speter      else
376350276Speter	/* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
376450276Speter	   because this is already executed in a page navigation
3765166124Srafan	   context that contains field navigation
376650276Speter	 */
376750276Speter	res = FN_First_Field(form);
376850276Speter    }
3769166124Srafan  return (res);
377050276Speter}
377150276Speter
377250276Speter/*---------------------------------------------------------------------------
3773166124Srafan|   Facility      :  libnform
377450276Speter|   Function      :  static int Next_Page_Number(const FORM * form)
3775166124Srafan|
377650276Speter|   Description   :  Calculate the page number following the current page
377750276Speter|                    number. This cycles if the highest page number is
3778166124Srafan|                    reached.
377950276Speter|
378050276Speter|   Return Values :  The next page number
378150276Speter+--------------------------------------------------------------------------*/
3782166124SrafanNCURSES_INLINE static int
3783166124SrafanNext_Page_Number(const FORM *form)
378450276Speter{
378550276Speter  return (form->curpage + 1) % form->maxpage;
378650276Speter}
378750276Speter
378850276Speter/*---------------------------------------------------------------------------
3789166124Srafan|   Facility      :  libnform
379050276Speter|   Function      :  static int Previous_Page_Number(const FORM * form)
3791166124Srafan|
379250276Speter|   Description   :  Calculate the page number before the current page
379350276Speter|                    number. This cycles if the first page number is
3794166124Srafan|                    reached.
379550276Speter|
379650276Speter|   Return Values :  The previous page number
379750276Speter+--------------------------------------------------------------------------*/
3798166124SrafanNCURSES_INLINE static int
3799166124SrafanPrevious_Page_Number(const FORM *form)
380050276Speter{
3801166124Srafan  return (form->curpage != 0 ? form->curpage - 1 : form->maxpage - 1);
380250276Speter}
3803166124Srafan
380450276Speter/*----------------------------------------------------------------------------
3805166124Srafan  Page Navigation routines
380650276Speter  --------------------------------------------------------------------------*/
380750276Speter
380850276Speter/*---------------------------------------------------------------------------
3809166124Srafan|   Facility      :  libnform
381050276Speter|   Function      :  static int Page_Navigation(
381150276Speter|                                               int (* const fct) (FORM *),
381250276Speter|                                               FORM * form)
3813166124Srafan|
3814166124Srafan|   Description   :  Generic behavior for changing a page. This means
381550276Speter|                    that the field is left and a new field is entered.
381650276Speter|                    So the field must be validated and the field init/term
381750276Speter|                    hooks must be called. Because also the page is changed,
381850276Speter|                    the forms init/term hooks must be called also.
381950276Speter|
382050276Speter|   Return Values :  E_OK                - success
382150276Speter|                    E_INVALID_FIELD     - field is invalid
382250276Speter|                    some other          - error from subordinate call
382350276Speter+--------------------------------------------------------------------------*/
3824166124Srafanstatic int
3825166124SrafanPage_Navigation(int (*const fct) (FORM *), FORM *form)
382650276Speter{
382750276Speter  int res;
382850276Speter
3829166124Srafan  if (!_nc_Internal_Validation(form))
383050276Speter    res = E_INVALID_FIELD;
383150276Speter  else
383250276Speter    {
3833166124Srafan      Call_Hook(form, fieldterm);
3834166124Srafan      Call_Hook(form, formterm);
383550276Speter      res = fct(form);
3836166124Srafan      Call_Hook(form, forminit);
3837166124Srafan      Call_Hook(form, fieldinit);
383850276Speter    }
383950276Speter  return res;
384050276Speter}
384150276Speter
384250276Speter/*---------------------------------------------------------------------------
3843166124Srafan|   Facility      :  libnform
384450276Speter|   Function      :  static int PN_Next_Page(FORM * form)
3845166124Srafan|
384650276Speter|   Description   :  Move to the next page of the form
384750276Speter|
384850276Speter|   Return Values :  E_OK                - success
384950276Speter|                    != E_OK             - error from subordinate call
385050276Speter+--------------------------------------------------------------------------*/
3851166124Srafanstatic int
3852166124SrafanPN_Next_Page(FORM *form)
3853166124Srafan{
3854166124Srafan  T((T_CALLED("PN_Next_Page(%p)"), form));
3855166124Srafan  returnCode(_nc_Set_Form_Page(form, Next_Page_Number(form), (FIELD *)0));
385650276Speter}
385750276Speter
385850276Speter/*---------------------------------------------------------------------------
3859166124Srafan|   Facility      :  libnform
386050276Speter|   Function      :  static int PN_Previous_Page(FORM * form)
3861166124Srafan|
386250276Speter|   Description   :  Move to the previous page of the form
386350276Speter|
386450276Speter|   Return Values :  E_OK              - success
386550276Speter|                    != E_OK           - error from subordinate call
386650276Speter+--------------------------------------------------------------------------*/
3867166124Srafanstatic int
3868166124SrafanPN_Previous_Page(FORM *form)
386950276Speter{
3870166124Srafan  T((T_CALLED("PN_Previous_Page(%p)"), form));
3871166124Srafan  returnCode(_nc_Set_Form_Page(form, Previous_Page_Number(form), (FIELD *)0));
387250276Speter}
387350276Speter
387450276Speter/*---------------------------------------------------------------------------
3875166124Srafan|   Facility      :  libnform
387650276Speter|   Function      :  static int PN_First_Page(FORM * form)
3877166124Srafan|
387850276Speter|   Description   :  Move to the first page of the form
387950276Speter|
388050276Speter|   Return Values :  E_OK              - success
388150276Speter|                    != E_OK           - error from subordinate call
388250276Speter+--------------------------------------------------------------------------*/
3883166124Srafanstatic int
3884166124SrafanPN_First_Page(FORM *form)
388550276Speter{
3886166124Srafan  T((T_CALLED("PN_First_Page(%p)"), form));
3887166124Srafan  returnCode(_nc_Set_Form_Page(form, 0, (FIELD *)0));
388850276Speter}
388950276Speter
389050276Speter/*---------------------------------------------------------------------------
3891166124Srafan|   Facility      :  libnform
389250276Speter|   Function      :  static int PN_Last_Page(FORM * form)
3893166124Srafan|
389450276Speter|   Description   :  Move to the last page of the form
389550276Speter|
389650276Speter|   Return Values :  E_OK              - success
389750276Speter|                    != E_OK           - error from subordinate call
389850276Speter+--------------------------------------------------------------------------*/
3899166124Srafanstatic int
3900166124SrafanPN_Last_Page(FORM *form)
390150276Speter{
3902166124Srafan  T((T_CALLED("PN_Last_Page(%p)"), form));
3903166124Srafan  returnCode(_nc_Set_Form_Page(form, form->maxpage - 1, (FIELD *)0));
390450276Speter}
3905166124Srafan
390650276Speter/*----------------------------------------------------------------------------
3907166124Srafan  END of Field Navigation routines
390850276Speter  --------------------------------------------------------------------------*/
3909166124Srafan
391050276Speter/*----------------------------------------------------------------------------
391150276Speter  Helper routines for the core form driver.
391250276Speter  --------------------------------------------------------------------------*/
391350276Speter
391450276Speter/*---------------------------------------------------------------------------
3915166124Srafan|   Facility      :  libnform
391650276Speter|   Function      :  static int Data_Entry(FORM * form,int c)
3917166124Srafan|
391850276Speter|   Description   :  Enter character c into at the current position of the
391950276Speter|                    current field of the form.
392050276Speter|
3921166124Srafan|   Return Values :  E_OK              - success
3922166124Srafan|                    E_REQUEST_DENIED  - driver could not process the request
392350276Speter|                    E_SYSTEM_ERROR    -
392450276Speter+--------------------------------------------------------------------------*/
3925166124Srafanstatic int
3926166124SrafanData_Entry(FORM *form, int c)
392750276Speter{
3928166124Srafan  FIELD *field = form->current;
392950276Speter  int result = E_REQUEST_DENIED;
393050276Speter
3931166124Srafan  T((T_CALLED("Data_Entry(%p,%s)"), form, _tracechtype((chtype)c)));
3932166124Srafan  if ((field->opts & O_EDIT)
393350276Speter#if FIX_FORM_INACTIVE_BUG
3934166124Srafan      && (field->opts & O_ACTIVE)
393550276Speter#endif
3936166124Srafan    )
393750276Speter    {
3938166124Srafan      if ((field->opts & O_BLANK) &&
3939166124Srafan	  First_Position_In_Current_Field(form) &&
3940166124Srafan	  !(form->status & _FCHECK_REQUIRED) &&
3941166124Srafan	  !(form->status & _WINDOW_MODIFIED))
394250276Speter	werase(form->w);
394350276Speter
394450276Speter      if (form->status & _OVLMODE)
394550276Speter	{
3946166124Srafan	  waddch(form->w, (chtype)c);
3947166124Srafan	}
3948166124Srafan      else
3949166124Srafan	/* no _OVLMODE */
395050276Speter	{
395150276Speter	  bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
395250276Speter
395350276Speter	  if (!(There_Is_Room ||
395450276Speter		((Single_Line_Field(field) && Growable(field)))))
3955166124Srafan	    RETURN(E_REQUEST_DENIED);
395650276Speter
3957166124Srafan	  if (!There_Is_Room && !Field_Grown(field, 1))
3958166124Srafan	    RETURN(E_SYSTEM_ERROR);
395950276Speter
3960166124Srafan	  winsch(form->w, (chtype)c);
396150276Speter	}
396250276Speter
3963166124Srafan      if ((result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form)) == E_OK)
396450276Speter	{
3965166124Srafan	  bool End_Of_Field = (((field->drows - 1) == form->currow) &&
3966166124Srafan			       ((field->dcols - 1) == form->curcol));
3967166124Srafan
396850276Speter	  form->status |= _WINDOW_MODIFIED;
396950276Speter	  if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3970166124Srafan	    result = Inter_Field_Navigation(FN_Next_Field, form);
397150276Speter	  else
397250276Speter	    {
3973166124Srafan	      if (End_Of_Field && Growable(field) && !Field_Grown(field, 1))
397450276Speter		result = E_SYSTEM_ERROR;
397550276Speter	      else
397650276Speter		{
3977166124Srafan#if USE_WIDEC_SUPPORT
3978166124Srafan		  /*
3979166124Srafan		   * We have just added a byte to the form field.  It may have
3980166124Srafan		   * been part of a multibyte character.  If it was, the
3981166124Srafan		   * addch_used field is nonzero and we should not try to move
3982166124Srafan		   * to a new column.
3983166124Srafan		   */
3984166124Srafan		  if (WINDOW_EXT(form->w, addch_used) == 0)
3985166124Srafan		    IFN_Next_Character(form);
3986166124Srafan#else
398750276Speter		  IFN_Next_Character(form);
3988166124Srafan#endif
398950276Speter		  result = E_OK;
399050276Speter		}
399150276Speter	    }
399250276Speter	}
399350276Speter    }
3994166124Srafan  RETURN(result);
399550276Speter}
3996166124Srafan
399750276Speter/* Structure to describe the binding of a request code to a function.
399850276Speter   The member keycode codes the request value as well as the generic
399950276Speter   routine to use for the request. The code for the generic routine
400050276Speter   is coded in the upper 16 Bits while the request code is coded in
4001166124Srafan   the lower 16 bits.
400250276Speter
400350276Speter   In terms of C++ you might think of a request as a class with a
400450276Speter   virtual method "perform". The different types of request are
400550276Speter   derived from this base class and overload (or not) the base class
400650276Speter   implementation of perform.
400750276Speter*/
4008166124Srafantypedef struct
4009166124Srafan{
4010166124Srafan  int keycode;			/* must be at least 32 bit: hi:mode, lo: key */
4011166124Srafan  int (*cmd) (FORM *);		/* low level driver routine for this key     */
4012166124Srafan}
4013166124SrafanBinding_Info;
401450276Speter
401550276Speter/* You may see this is the class-id of the request type class */
4016166124Srafan#define ID_PN    (0x00000000)	/* Page navigation           */
4017166124Srafan#define ID_FN    (0x00010000)	/* Inter-Field navigation    */
4018166124Srafan#define ID_IFN   (0x00020000)	/* Intra-Field navigation    */
4019166124Srafan#define ID_VSC   (0x00030000)	/* Vertical Scrolling        */
4020166124Srafan#define ID_HSC   (0x00040000)	/* Horizontal Scrolling      */
4021166124Srafan#define ID_FE    (0x00050000)	/* Field Editing             */
4022166124Srafan#define ID_EM    (0x00060000)	/* Edit Mode                 */
4023166124Srafan#define ID_FV    (0x00070000)	/* Field Validation          */
4024166124Srafan#define ID_CH    (0x00080000)	/* Choice                    */
402550276Speter#define ID_Mask  (0xffff0000)
402650276Speter#define Key_Mask (0x0000ffff)
402750276Speter#define ID_Shft  (16)
402850276Speter
402950276Speter/* This array holds all the Binding Infos */
4030166124Srafan/* *INDENT-OFF* */
4031166124Srafanstatic const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
403250276Speter{
403350276Speter  { REQ_NEXT_PAGE    |ID_PN  ,PN_Next_Page},
403450276Speter  { REQ_PREV_PAGE    |ID_PN  ,PN_Previous_Page},
403550276Speter  { REQ_FIRST_PAGE   |ID_PN  ,PN_First_Page},
403650276Speter  { REQ_LAST_PAGE    |ID_PN  ,PN_Last_Page},
4037166124Srafan
403850276Speter  { REQ_NEXT_FIELD   |ID_FN  ,FN_Next_Field},
403950276Speter  { REQ_PREV_FIELD   |ID_FN  ,FN_Previous_Field},
404050276Speter  { REQ_FIRST_FIELD  |ID_FN  ,FN_First_Field},
404150276Speter  { REQ_LAST_FIELD   |ID_FN  ,FN_Last_Field},
404250276Speter  { REQ_SNEXT_FIELD  |ID_FN  ,FN_Sorted_Next_Field},
404350276Speter  { REQ_SPREV_FIELD  |ID_FN  ,FN_Sorted_Previous_Field},
404450276Speter  { REQ_SFIRST_FIELD |ID_FN  ,FN_Sorted_First_Field},
404550276Speter  { REQ_SLAST_FIELD  |ID_FN  ,FN_Sorted_Last_Field},
404650276Speter  { REQ_LEFT_FIELD   |ID_FN  ,FN_Left_Field},
404750276Speter  { REQ_RIGHT_FIELD  |ID_FN  ,FN_Right_Field},
404850276Speter  { REQ_UP_FIELD     |ID_FN  ,FN_Up_Field},
404950276Speter  { REQ_DOWN_FIELD   |ID_FN  ,FN_Down_Field},
4050166124Srafan
405150276Speter  { REQ_NEXT_CHAR    |ID_IFN ,IFN_Next_Character},
405250276Speter  { REQ_PREV_CHAR    |ID_IFN ,IFN_Previous_Character},
405350276Speter  { REQ_NEXT_LINE    |ID_IFN ,IFN_Next_Line},
405450276Speter  { REQ_PREV_LINE    |ID_IFN ,IFN_Previous_Line},
405550276Speter  { REQ_NEXT_WORD    |ID_IFN ,IFN_Next_Word},
405650276Speter  { REQ_PREV_WORD    |ID_IFN ,IFN_Previous_Word},
405750276Speter  { REQ_BEG_FIELD    |ID_IFN ,IFN_Beginning_Of_Field},
405850276Speter  { REQ_END_FIELD    |ID_IFN ,IFN_End_Of_Field},
405950276Speter  { REQ_BEG_LINE     |ID_IFN ,IFN_Beginning_Of_Line},
406050276Speter  { REQ_END_LINE     |ID_IFN ,IFN_End_Of_Line},
406150276Speter  { REQ_LEFT_CHAR    |ID_IFN ,IFN_Left_Character},
406250276Speter  { REQ_RIGHT_CHAR   |ID_IFN ,IFN_Right_Character},
406350276Speter  { REQ_UP_CHAR      |ID_IFN ,IFN_Up_Character},
406450276Speter  { REQ_DOWN_CHAR    |ID_IFN ,IFN_Down_Character},
4065166124Srafan
406650276Speter  { REQ_NEW_LINE     |ID_FE  ,FE_New_Line},
406750276Speter  { REQ_INS_CHAR     |ID_FE  ,FE_Insert_Character},
406850276Speter  { REQ_INS_LINE     |ID_FE  ,FE_Insert_Line},
406950276Speter  { REQ_DEL_CHAR     |ID_FE  ,FE_Delete_Character},
407050276Speter  { REQ_DEL_PREV     |ID_FE  ,FE_Delete_Previous},
407150276Speter  { REQ_DEL_LINE     |ID_FE  ,FE_Delete_Line},
407250276Speter  { REQ_DEL_WORD     |ID_FE  ,FE_Delete_Word},
407350276Speter  { REQ_CLR_EOL      |ID_FE  ,FE_Clear_To_End_Of_Line},
4074166124Srafan  { REQ_CLR_EOF      |ID_FE  ,FE_Clear_To_End_Of_Field},
407550276Speter  { REQ_CLR_FIELD    |ID_FE  ,FE_Clear_Field},
4076166124Srafan
407750276Speter  { REQ_OVL_MODE     |ID_EM  ,EM_Overlay_Mode},
407850276Speter  { REQ_INS_MODE     |ID_EM  ,EM_Insert_Mode},
4079166124Srafan
408050276Speter  { REQ_SCR_FLINE    |ID_VSC ,VSC_Scroll_Line_Forward},
408150276Speter  { REQ_SCR_BLINE    |ID_VSC ,VSC_Scroll_Line_Backward},
408250276Speter  { REQ_SCR_FPAGE    |ID_VSC ,VSC_Scroll_Page_Forward},
408350276Speter  { REQ_SCR_BPAGE    |ID_VSC ,VSC_Scroll_Page_Backward},
408450276Speter  { REQ_SCR_FHPAGE   |ID_VSC ,VSC_Scroll_Half_Page_Forward},
408550276Speter  { REQ_SCR_BHPAGE   |ID_VSC ,VSC_Scroll_Half_Page_Backward},
4086166124Srafan
408750276Speter  { REQ_SCR_FCHAR    |ID_HSC ,HSC_Scroll_Char_Forward},
408850276Speter  { REQ_SCR_BCHAR    |ID_HSC ,HSC_Scroll_Char_Backward},
408950276Speter  { REQ_SCR_HFLINE   |ID_HSC ,HSC_Horizontal_Line_Forward},
409050276Speter  { REQ_SCR_HBLINE   |ID_HSC ,HSC_Horizontal_Line_Backward},
409150276Speter  { REQ_SCR_HFHALF   |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
409250276Speter  { REQ_SCR_HBHALF   |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
4093166124Srafan
409450276Speter  { REQ_VALIDATION   |ID_FV  ,FV_Validation},
409550276Speter
409650276Speter  { REQ_NEXT_CHOICE  |ID_CH  ,CR_Next_Choice},
409750276Speter  { REQ_PREV_CHOICE  |ID_CH  ,CR_Previous_Choice}
409850276Speter};
4099166124Srafan/* *INDENT-ON* */
410050276Speter
410150276Speter/*---------------------------------------------------------------------------
4102166124Srafan|   Facility      :  libnform
410350276Speter|   Function      :  int form_driver(FORM * form,int  c)
4104166124Srafan|
410550276Speter|   Description   :  This is the workhorse of the forms system. It checks
410650276Speter|                    to determine whether the character c is a request or
410750276Speter|                    data. If it is a request, the form driver executes
410850276Speter|                    the request and returns the result. If it is data
410950276Speter|                    (printable character), it enters the data into the
411050276Speter|                    current position in the current field. If it is not
411150276Speter|                    recognized, the form driver assumes it is an application
411250276Speter|                    defined command and returns E_UNKNOWN_COMMAND.
411350276Speter|                    Application defined command should be defined relative
411450276Speter|                    to MAX_FORM_COMMAND, the maximum value of a request.
411550276Speter|
411650276Speter|   Return Values :  E_OK              - success
411750276Speter|                    E_SYSTEM_ERROR    - system error
411850276Speter|                    E_BAD_ARGUMENT    - an argument is incorrect
411950276Speter|                    E_NOT_POSTED      - form is not posted
412050276Speter|                    E_INVALID_FIELD   - field contents are invalid
412150276Speter|                    E_BAD_STATE       - called from inside a hook routine
412250276Speter|                    E_REQUEST_DENIED  - request failed
4123166124Srafan|                    E_NOT_CONNECTED   - no fields are connected to the form
412450276Speter|                    E_UNKNOWN_COMMAND - command not known
412550276Speter+--------------------------------------------------------------------------*/
412676726SpeterNCURSES_EXPORT(int)
4127166124Srafanform_driver(FORM *form, int c)
412850276Speter{
4129166124Srafan  const Binding_Info *BI = (Binding_Info *) 0;
413050276Speter  int res = E_UNKNOWN_COMMAND;
413150276Speter
4132166124Srafan  T((T_CALLED("form_driver(%p,%d)"), form, c));
4133166124Srafan
413450276Speter  if (!form)
413550276Speter    RETURN(E_BAD_ARGUMENT);
413650276Speter
413750276Speter  if (!(form->field))
413850276Speter    RETURN(E_NOT_CONNECTED);
4139166124Srafan
414050276Speter  assert(form->page);
4141166124Srafan
4142166124Srafan  if (c == FIRST_ACTIVE_MAGIC)
414350276Speter    {
414450276Speter      form->current = _nc_First_Active_Field(form);
4145166124Srafan      RETURN(E_OK);
414650276Speter    }
4147166124Srafan
4148166124Srafan  assert(form->current &&
4149166124Srafan	 form->current->buf &&
415050276Speter	 (form->current->form == form)
4151166124Srafan    );
4152166124Srafan
4153166124Srafan  if (form->status & _IN_DRIVER)
415450276Speter    RETURN(E_BAD_STATE);
415550276Speter
4156166124Srafan  if (!(form->status & _POSTED))
415750276Speter    RETURN(E_NOT_POSTED);
4158166124Srafan
4159166124Srafan  if ((c >= MIN_FORM_COMMAND && c <= MAX_FORM_COMMAND) &&
4160166124Srafan      ((bindings[c - MIN_FORM_COMMAND].keycode & Key_Mask) == c))
4161166124Srafan    BI = &(bindings[c - MIN_FORM_COMMAND]);
4162166124Srafan
416350276Speter  if (BI)
416450276Speter    {
4165166124Srafan      typedef int (*Generic_Method) (int (*const) (FORM *), FORM *);
4166166124Srafan      static const Generic_Method Generic_Methods[] =
4167166124Srafan      {
4168166124Srafan	Page_Navigation,	/* overloaded to call field&form hooks */
4169166124Srafan	Inter_Field_Navigation,	/* overloaded to call field hooks      */
4170166124Srafan	NULL,			/* Intra-Field is generic              */
4171166124Srafan	Vertical_Scrolling,	/* Overloaded to check multi-line      */
4172166124Srafan	Horizontal_Scrolling,	/* Overloaded to check single-line     */
4173166124Srafan	Field_Editing,		/* Overloaded to mark modification     */
4174166124Srafan	NULL,			/* Edit Mode is generic                */
4175166124Srafan	NULL,			/* Field Validation is generic         */
4176166124Srafan	NULL			/* Choice Request is generic           */
4177166124Srafan      };
4178166124Srafan      size_t nMethods = (sizeof(Generic_Methods) / sizeof(Generic_Methods[0]));
4179184989Srafan      size_t method = (BI->keycode >> ID_Shft) & 0xffff;	/* see ID_Mask */
4180166124Srafan
4181166124Srafan      if ((method >= nMethods) || !(BI->cmd))
418250276Speter	res = E_SYSTEM_ERROR;
418350276Speter      else
418450276Speter	{
418550276Speter	  Generic_Method fct = Generic_Methods[method];
4186166124Srafan
418750276Speter	  if (fct)
4188166124Srafan	    res = fct(BI->cmd, form);
418950276Speter	  else
4190166124Srafan	    res = (BI->cmd) (form);
419150276Speter	}
4192166124Srafan    }
4193174993Srafan#ifdef NCURSES_MOUSE_VERSION
4194174993Srafan  else if (KEY_MOUSE == c)
4195174993Srafan    {
4196174993Srafan      MEVENT event;
4197174993Srafan      WINDOW *win = form->win ? form->win : stdscr;
4198174993Srafan      WINDOW *sub = form->sub ? form->sub : win;
4199174993Srafan
4200174993Srafan      getmouse(&event);
4201174993Srafan      if ((event.bstate & (BUTTON1_CLICKED |
4202174993Srafan			   BUTTON1_DOUBLE_CLICKED |
4203174993Srafan			   BUTTON1_TRIPLE_CLICKED))
4204174993Srafan	  && wenclose(win, event.y, event.x))
4205174993Srafan	{			/* we react only if the click was in the userwin, that means
4206174993Srafan				 * inside the form display area or at the decoration window.
4207174993Srafan				 */
4208174993Srafan	  int ry = event.y, rx = event.x;	/* screen coordinates */
4209174993Srafan
4210174993Srafan	  res = E_REQUEST_DENIED;
4211174993Srafan	  if (mouse_trafo(&ry, &rx, FALSE))
4212174993Srafan	    {			/* rx, ry are now "curses" coordinates */
4213174993Srafan	      if (ry < sub->_begy)
4214174993Srafan		{		/* we clicked above the display region; this is
4215174993Srafan				 * interpreted as "scroll up" request
4216174993Srafan				 */
4217174993Srafan		  if (event.bstate & BUTTON1_CLICKED)
4218174993Srafan		    res = form_driver(form, REQ_PREV_FIELD);
4219174993Srafan		  else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4220174993Srafan		    res = form_driver(form, REQ_PREV_PAGE);
4221174993Srafan		  else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4222174993Srafan		    res = form_driver(form, REQ_FIRST_FIELD);
4223174993Srafan		}
4224174993Srafan	      else if (ry > sub->_begy + sub->_maxy)
4225174993Srafan		{		/* we clicked below the display region; this is
4226174993Srafan				 * interpreted as "scroll down" request
4227174993Srafan				 */
4228174993Srafan		  if (event.bstate & BUTTON1_CLICKED)
4229174993Srafan		    res = form_driver(form, REQ_NEXT_FIELD);
4230174993Srafan		  else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
4231174993Srafan		    res = form_driver(form, REQ_NEXT_PAGE);
4232174993Srafan		  else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
4233174993Srafan		    res = form_driver(form, REQ_LAST_FIELD);
4234174993Srafan		}
4235174993Srafan	      else if (wenclose(sub, event.y, event.x))
4236174993Srafan		{		/* Inside the area we try to find the hit item */
4237174993Srafan		  int i;
4238174993Srafan
4239174993Srafan		  ry = event.y;
4240174993Srafan		  rx = event.x;
4241174993Srafan		  if (wmouse_trafo(sub, &ry, &rx, FALSE))
4242174993Srafan		    {
4243174993Srafan		      int min_field = form->page[form->curpage].pmin;
4244174993Srafan		      int max_field = form->page[form->curpage].pmax;
4245174993Srafan
4246174993Srafan		      for (i = min_field; i <= max_field; ++i)
4247174993Srafan			{
4248174993Srafan			  FIELD *field = form->field[i];
4249174993Srafan
4250174993Srafan			  if (Field_Is_Selectable(field)
4251174993Srafan			      && Field_encloses(field, ry, rx) == E_OK)
4252174993Srafan			    {
4253174993Srafan			      res = _nc_Set_Current_Field(form, field);
4254174993Srafan			      if (res == E_OK)
4255174993Srafan				res = _nc_Position_Form_Cursor(form);
4256174993Srafan			      if (res == E_OK
4257174993Srafan				  && (event.bstate & BUTTON1_DOUBLE_CLICKED))
4258174993Srafan				res = E_UNKNOWN_COMMAND;
4259174993Srafan			      break;
4260174993Srafan			    }
4261174993Srafan			}
4262174993Srafan		    }
4263174993Srafan		}
4264174993Srafan	    }
4265174993Srafan	}
4266174993Srafan      else
4267174993Srafan	res = E_REQUEST_DENIED;
4268174993Srafan    }
4269174993Srafan#endif /* NCURSES_MOUSE_VERSION */
4270166124Srafan  else if (!(c & (~(int)MAX_REGULAR_CHARACTER)))
427150276Speter    {
4272166124Srafan      /*
4273166124Srafan       * If we're using 8-bit characters, iscntrl+isprint cover the whole set.
4274166124Srafan       * But with multibyte characters, there is a third possibility, i.e.,
4275166124Srafan       * parts of characters that build up into printable characters which are
4276166124Srafan       * not considered printable.
4277166124Srafan       *
4278166124Srafan       * FIXME: the wide-character branch should also use Check_Char().
4279166124Srafan       */
4280166124Srafan#if USE_WIDEC_SUPPORT
4281166124Srafan      if (!iscntrl(UChar(c)))
4282166124Srafan#else
4283166124Srafan      if (isprint(UChar(c)) &&
4284166124Srafan	  Check_Char(form->current->type, c,
428550276Speter		     (TypeArgument *)(form->current->arg)))
4286166124Srafan#endif
4287166124Srafan	res = Data_Entry(form, c);
428850276Speter    }
428950276Speter  _nc_Refresh_Current_Field(form);
429050276Speter  RETURN(res);
429150276Speter}
4292166124Srafan
429350276Speter/*----------------------------------------------------------------------------
429450276Speter  Field-Buffer manipulation routines.
4295166124Srafan  The effects of setting a buffer are tightly coupled to the core of the form
429650276Speter  driver logic. This is especially true in the case of growable fields.
4297166124Srafan  So I don't separate this into a separate module.
429850276Speter  --------------------------------------------------------------------------*/
429950276Speter
430050276Speter/*---------------------------------------------------------------------------
4301166124Srafan|   Facility      :  libnform
430250276Speter|   Function      :  int set_field_buffer(FIELD *field,
430350276Speter|                                         int buffer, char *value)
4304166124Srafan|
430550276Speter|   Description   :  Set the given buffer of the field to the given value.
430650276Speter|                    Buffer 0 stores the displayed content of the field.
430750276Speter|                    For dynamic fields this may grow the fieldbuffers if
430850276Speter|                    the length of the value exceeds the current buffer
430950276Speter|                    length. For buffer 0 only printable values are allowed.
431050276Speter|                    For static fields, the value needs not to be zero ter-
4311166124Srafan|                    minated. It is copied up to the length of the buffer.
431250276Speter|
431350276Speter|   Return Values :  E_OK            - success
431450276Speter|                    E_BAD_ARGUMENT  - invalid argument
431550276Speter|                    E_SYSTEM_ERROR  - system error
431650276Speter+--------------------------------------------------------------------------*/
431776726SpeterNCURSES_EXPORT(int)
4318166124Srafanset_field_buffer(FIELD *field, int buffer, const char *value)
431950276Speter{
4320166124Srafan  FIELD_CELL *p;
432150276Speter  int res = E_OK;
4322166124Srafan  unsigned int i;
432350276Speter  unsigned int len;
432450276Speter
4325166124Srafan#if USE_WIDEC_SUPPORT
4326166124Srafan  FIELD_CELL *widevalue = 0;
4327166124Srafan#endif
4328166124Srafan
4329166124Srafan  T((T_CALLED("set_field_buffer(%p,%d,%s)"), field, buffer, _nc_visbuf(value)));
4330166124Srafan
4331166124Srafan  if (!field || !value || ((buffer < 0) || (buffer > field->nbuf)))
433250276Speter    RETURN(E_BAD_ARGUMENT);
433350276Speter
4334166124Srafan  len = Buffer_Length(field);
433550276Speter
433650276Speter  if (Growable(field))
433750276Speter    {
433850276Speter      /* for a growable field we must assume zero terminated strings, because
4339166124Srafan         somehow we have to detect the length of what should be copied.
4340166124Srafan       */
434150276Speter      unsigned int vlen = strlen(value);
4342166124Srafan
434350276Speter      if (vlen > len)
434450276Speter	{
434550276Speter	  if (!Field_Grown(field,
4346166124Srafan			   (int)(1 + (vlen - len) / ((field->rows + field->nrow)
4347166124Srafan						     * field->cols))))
434850276Speter	    RETURN(E_SYSTEM_ERROR);
434950276Speter
435050276Speter	  len = vlen;
435150276Speter	}
435250276Speter    }
435350276Speter
4354166124Srafan  p = Address_Of_Nth_Buffer(field, buffer);
4355166124Srafan
4356166124Srafan#if USE_WIDEC_SUPPORT
4357166124Srafan  /*
4358166124Srafan   * Use addstr's logic for converting a string to an array of cchar_t's.
4359166124Srafan   * There should be a better way, but this handles nonspacing characters
4360166124Srafan   * and other special cases that we really do not want to handle here.
4361166124Srafan   */
4362184989Srafan#if NCURSES_EXT_FUNCS
4363184989Srafan  if (wresize(field->working, field->drows, field->dcols) == ERR)
4364184989Srafan#endif
4365184989Srafan    {
4366184989Srafan      delwin(field->working);
4367184989Srafan      field->working = newpad(field->drows, field->dcols);
4368184989Srafan    }
4369166124Srafan  wclear(field->working);
4370166124Srafan  mvwaddstr(field->working, 0, 0, value);
4371166124Srafan
4372174993Srafan  if ((widevalue = typeCalloc(FIELD_CELL, len + 1)) == 0)
4373166124Srafan    {
4374166124Srafan      RETURN(E_SYSTEM_ERROR);
4375166124Srafan    }
4376166124Srafan  else
4377166124Srafan    {
4378184989Srafan      for (i = 0; i < (unsigned)field->drows; ++i)
4379184989Srafan	{
4380184989Srafan	  mvwin_wchnstr(field->working, i, 0,
4381184989Srafan			widevalue + (i * field->dcols),
4382184989Srafan			field->dcols);
4383184989Srafan	}
4384166124Srafan      for (i = 0; i < len; ++i)
4385166124Srafan	{
4386166124Srafan	  if (CharEq(myZEROS, widevalue[i]))
4387166124Srafan	    {
4388166124Srafan	      while (i < len)
4389166124Srafan		p[i++] = myBLANK;
4390166124Srafan	      break;
4391166124Srafan	    }
4392166124Srafan	  p[i] = widevalue[i];
4393166124Srafan	}
4394166124Srafan      free(widevalue);
4395166124Srafan    }
439650276Speter#else
4397166124Srafan  for (i = 0; i < len; ++i)
439850276Speter    {
4399166124Srafan      if (value[i] == '\0')
4400166124Srafan	{
4401166124Srafan	  while (i < len)
4402166124Srafan	    p[i++] = myBLANK;
4403166124Srafan	  break;
4404166124Srafan	}
4405166124Srafan      p[i] = value[i];
440650276Speter    }
440750276Speter#endif
440850276Speter
4409166124Srafan  if (buffer == 0)
441050276Speter    {
441150276Speter      int syncres;
4412166124Srafan
4413166124Srafan      if (((syncres = Synchronize_Field(field)) != E_OK) &&
4414166124Srafan	  (res == E_OK))
441550276Speter	res = syncres;
4416166124Srafan      if (((syncres = Synchronize_Linked_Fields(field)) != E_OK) &&
4417166124Srafan	  (res == E_OK))
441850276Speter	res = syncres;
441950276Speter    }
442050276Speter  RETURN(res);
4421166124Srafan}
442250276Speter
442350276Speter/*---------------------------------------------------------------------------
4424166124Srafan|   Facility      :  libnform
442550276Speter|   Function      :  char *field_buffer(const FIELD *field,int buffer)
4426166124Srafan|
442750276Speter|   Description   :  Return the address of the buffer for the field.
442850276Speter|
442950276Speter|   Return Values :  Pointer to buffer or NULL if arguments were invalid.
443050276Speter+--------------------------------------------------------------------------*/
443176726SpeterNCURSES_EXPORT(char *)
4432166124Srafanfield_buffer(const FIELD *field, int buffer)
443350276Speter{
4434166124Srafan  char *result = 0;
4435166124Srafan
4436166124Srafan  T((T_CALLED("field_buffer(%p,%d)"), field, buffer));
4437166124Srafan
443850276Speter  if (field && (buffer >= 0) && (buffer <= field->nbuf))
4439166124Srafan    {
4440166124Srafan#if USE_WIDEC_SUPPORT
4441166124Srafan      FIELD_CELL *data = Address_Of_Nth_Buffer(field, buffer);
4442166124Srafan      unsigned need = 0;
4443166124Srafan      int size = Buffer_Length(field);
4444166124Srafan      int n;
4445166124Srafan
4446166124Srafan      /* determine the number of bytes needed to store the expanded string */
4447166124Srafan      for (n = 0; n < size; ++n)
4448166124Srafan	{
4449166124Srafan	  if (!isWidecExt(data[n]))
4450166124Srafan	    {
4451166124Srafan	      mbstate_t state;
4452166124Srafan	      size_t next;
4453166124Srafan
4454166124Srafan	      init_mb(state);
4455166124Srafan	      next = _nc_wcrtomb(0, data[n].chars[0], &state);
4456166124Srafan	      if (!isEILSEQ(next))
4457174993Srafan		need += next;
4458166124Srafan	    }
4459166124Srafan	}
4460166124Srafan
4461166124Srafan      /* allocate a place to store the expanded string */
4462166124Srafan      if (field->expanded[buffer] != 0)
4463166124Srafan	free(field->expanded[buffer]);
4464166124Srafan      field->expanded[buffer] = typeMalloc(char, need + 1);
4465166124Srafan
4466166124Srafan      /* expand the multibyte data */
4467166124Srafan      if ((result = field->expanded[buffer]) != 0)
4468166124Srafan	{
4469166124Srafan	  wclear(field->working);
4470166124Srafan	  mvwadd_wchnstr(field->working, 0, 0, data, size);
4471174993Srafan	  mvwinnstr(field->working, 0, 0, result, (int)need);
4472166124Srafan	}
4473166124Srafan#else
4474166124Srafan      result = Address_Of_Nth_Buffer(field, buffer);
4475166124Srafan#endif
4476166124Srafan    }
4477166124Srafan  returnPtr(result);
447850276Speter}
447950276Speter
4480166124Srafan#if USE_WIDEC_SUPPORT
4481166124Srafan
4482166124Srafan/* FIXME: see lib_get_wch.c */
4483166124Srafan#if HAVE_MBTOWC && HAVE_MBLEN
4484166124Srafan#define reset_mbytes(state) mblen(NULL, 0), mbtowc(NULL, NULL, 0)
4485166124Srafan#define count_mbytes(buffer,length,state) mblen(buffer,length)
4486166124Srafan#define trans_mbytes(wch,buffer,length,state) \
4487166124Srafan	(int) mbtowc(&wch, buffer, length)
4488166124Srafan#elif HAVE_MBRTOWC && HAVE_MBRLEN
4489166124Srafan#define NEED_STATE
4490166124Srafan#define reset_mbytes(state) init_mb(state)
4491166124Srafan#define count_mbytes(buffer,length,state) mbrlen(buffer,length,&state)
4492166124Srafan#define trans_mbytes(wch,buffer,length,state) \
4493166124Srafan	(int) mbrtowc(&wch, buffer, length, &state)
4494166124Srafan#else
4495166124Srafanmake an error
4496166124Srafan#endif
4497166124Srafan
4498166124Srafan/*---------------------------------------------------------------------------
4499166124Srafan| Convert a multibyte string to a wide-character string.  The result must be
4500166124Srafan| freed by the caller.
4501166124Srafan+--------------------------------------------------------------------------*/
4502166124SrafanNCURSES_EXPORT(wchar_t *)
4503166124Srafan_nc_Widen_String(char *source, int *lengthp)
4504166124Srafan{
4505166124Srafan  wchar_t *result = 0;
4506166124Srafan  wchar_t wch;
4507166124Srafan  size_t given = strlen(source);
4508166124Srafan  size_t tries;
4509166124Srafan  int pass;
4510166124Srafan  int status;
4511166124Srafan
4512166124Srafan#ifdef NEED_STATE
4513166124Srafan  mbstate_t state;
4514166124Srafan#endif
4515166124Srafan
4516166124Srafan  for (pass = 0; pass < 2; ++pass)
4517166124Srafan    {
4518166124Srafan      unsigned need = 0;
4519166124Srafan      size_t passed = 0;
4520166124Srafan
4521166124Srafan      while (passed < given)
4522166124Srafan	{
4523166124Srafan	  bool found = FALSE;
4524166124Srafan
4525166124Srafan	  for (tries = 1, status = 0; tries <= (given - passed); ++tries)
4526166124Srafan	    {
4527166124Srafan	      int save = source[passed + tries];
4528166124Srafan
4529166124Srafan	      source[passed + tries] = 0;
4530166124Srafan	      reset_mbytes(state);
4531166124Srafan	      status = trans_mbytes(wch, source + passed, tries, state);
4532166124Srafan	      source[passed + tries] = save;
4533166124Srafan
4534166124Srafan	      if (status > 0)
4535166124Srafan		{
4536166124Srafan		  found = TRUE;
4537166124Srafan		  break;
4538166124Srafan		}
4539166124Srafan	    }
4540166124Srafan	  if (found)
4541166124Srafan	    {
4542166124Srafan	      if (pass)
4543166124Srafan		{
4544166124Srafan		  result[need] = wch;
4545166124Srafan		}
4546166124Srafan	      passed += status;
4547166124Srafan	      ++need;
4548166124Srafan	    }
4549166124Srafan	  else
4550166124Srafan	    {
4551166124Srafan	      if (pass)
4552166124Srafan		{
4553166124Srafan		  result[need] = source[passed];
4554166124Srafan		}
4555166124Srafan	      ++need;
4556166124Srafan	      ++passed;
4557166124Srafan	    }
4558166124Srafan	}
4559166124Srafan
4560166124Srafan      if (!pass)
4561166124Srafan	{
4562166124Srafan	  if (!need)
4563166124Srafan	    break;
4564166124Srafan	  result = typeCalloc(wchar_t, need);
4565166124Srafan
4566166124Srafan	  *lengthp = need;
4567166124Srafan	  if (result == 0)
4568166124Srafan	    break;
4569166124Srafan	}
4570166124Srafan    }
4571166124Srafan
4572166124Srafan  return result;
4573166124Srafan}
4574166124Srafan#endif
4575166124Srafan
457650276Speter/* frm_driver.c ends here */
4577