1 /****************************************************************************
2 * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Juergen Pfeifer, 1995,1997 *
31 ****************************************************************************/
33 #include "form.priv.h"
35 MODULE_ID("$Id: frm_driver.c,v 1.76 2006/11/04 18:45:35 tom Exp $")
37 /*----------------------------------------------------------------------------
38 This is the core module of the form library. It contains the majority
39 of the driver routines as well as the form_driver function.
41 Essentially this module is nearly the whole library. This is because
42 all the functions in this module depends on some others in the module,
43 so it makes no sense to split them into separate files because they
44 will always be linked together. The only acceptable concern is turnaround
45 time for this module, but now we have all Pentiums or RISCs, so what!
47 The driver routines are grouped into nine generic categories:
49 a) Page Navigation ( all functions prefixed by PN_ )
50 The current page of the form is left and some new page is
52 b) Inter-Field Navigation ( all functions prefixed by FN_ )
53 The current field of the form is left and some new field is
55 c) Intra-Field Navigation ( all functions prefixed by IFN_ )
56 The current position in the current field is changed.
57 d) Vertical Scrolling ( all functions prefixed by VSC_ )
58 Essentially this is a specialization of Intra-Field navigation.
59 It has to check for a multi-line field.
60 e) Horizontal Scrolling ( all functions prefixed by HSC_ )
61 Essentially this is a specialization of Intra-Field navigation.
62 It has to check for a single-line field.
63 f) Field Editing ( all functions prefixed by FE_ )
64 The content of the current field is changed
65 g) Edit Mode requests ( all functions prefixed by EM_ )
66 Switching between insert and overlay mode
67 h) Field-Validation requests ( all functions prefixed by FV_ )
68 Perform verifications of the field.
69 i) Choice requests ( all functions prefixed by CR_ )
70 Requests to enumerate possible field values
71 --------------------------------------------------------------------------*/
73 /*----------------------------------------------------------------------------
74 Some remarks on the placements of assert() macros :
75 I use them only on "strategic" places, i.e. top level entries where
76 I want to make sure that things are set correctly. Throughout subordinate
77 routines I omit them mostly.
78 --------------------------------------------------------------------------*/
81 Some options that may effect compatibility in behavior to SVr4 forms,
82 but they are here to allow a more intuitive and user friendly behavior of
83 our form implementation. This doesn't affect the API, so we feel it is
86 The initial implementation tries to stay very close with the behavior
87 of the original SVr4 implementation, although in some areas it is quite
88 clear that this isn't the most appropriate way. As far as possible this
89 sources will allow you to build a forms lib that behaves quite similar
90 to SVr4, but now and in the future we will give you better options.
91 Perhaps at some time we will make this configurable at runtime.
94 /* Implement a more user-friendly previous/next word behavior */
95 #define FRIENDLY_PREV_NEXT_WORD (1)
96 /* Fix the wrong behavior for forms with all fields inactive */
97 #define FIX_FORM_INACTIVE_BUG (1)
98 /* Allow dynamic field growth also when navigating past the end */
99 #define GROW_IF_NAVIGATE (1)
101 #if USE_WIDEC_SUPPORT
102 #define myADDNSTR(w, s, n) wadd_wchnstr(w, s, n)
103 #define myINSNSTR(w, s, n) wins_wchnstr(w, s, n)
104 #define myINNSTR(w, s, n) fix_wchnstr(w, s, n)
105 #define myWCWIDTH(w, y, x) cell_width(w, y, x)
107 #define myADDNSTR(w, s, n) waddnstr(w, s, n)
108 #define myINSNSTR(w, s, n) winsnstr(w, s, n)
109 #define myINNSTR(w, s, n) winnstr(w, s, n)
110 #define myWCWIDTH(w, y, x) 1
113 /*----------------------------------------------------------------------------
114 Forward references to some internally used static functions
115 --------------------------------------------------------------------------*/
116 static int Inter_Field_Navigation(int (*const fct) (FORM *), FORM *form);
117 static int FN_Next_Field(FORM *form);
118 static int FN_Previous_Field(FORM *form);
119 static int FE_New_Line(FORM *);
120 static int FE_Delete_Previous(FORM *);
122 /*----------------------------------------------------------------------------
125 Some Remarks on that: I use the convention to use UPPERCASE for constants
126 defined by Macros. If I provide a macro as a kind of inline routine to
127 provide some logic, I use my Upper_Lower case style.
128 --------------------------------------------------------------------------*/
130 /* Calculate the position of a single row in a field buffer */
131 #define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
133 /* Calculate start address for the fields buffer# N */
134 #define Address_Of_Nth_Buffer(field,N) \
135 ((field)->buf + (N)*(1+Buffer_Length(field)))
137 /* Calculate the start address of the row in the fields specified buffer# N */
138 #define Address_Of_Row_In_Nth_Buffer(field,N,row) \
139 (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
141 /* Calculate the start address of the row in the fields primary buffer */
142 #define Address_Of_Row_In_Buffer(field,row) \
143 Address_Of_Row_In_Nth_Buffer(field,0,row)
145 /* Calculate the start address of the row in the forms current field
147 #define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
148 Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
150 /* Calculate the start address of the row in the forms current field
152 #define Address_Of_Current_Row_In_Buffer(form) \
153 Address_Of_Current_Row_In_Nth_Buffer(form,0)
155 /* Calculate the address of the cursor in the forms current field
157 #define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
158 (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
160 /* Calculate the address of the cursor in the forms current field
162 #define Address_Of_Current_Position_In_Buffer(form) \
163 Address_Of_Current_Position_In_Nth_Buffer(form,0)
165 /* Logic to decide whether or not a field is actually a field with
166 vertical or horizontal scrolling */
167 #define Is_Scroll_Field(field) \
168 (((field)->drows > (field)->rows) || \
169 ((field)->dcols > (field)->cols))
171 /* Logic to decide whether or not a field needs to have an individual window
172 instead of a derived window because it contains invisible parts.
173 This is true for non-public fields and for scrollable fields. */
174 #define Has_Invisible_Parts(field) \
175 (!((field)->opts & O_PUBLIC) || \
176 Is_Scroll_Field(field))
178 /* Logic to decide whether or not a field needs justification */
179 #define Justification_Allowed(field) \
180 (((field)->just != NO_JUSTIFICATION) && \
181 (Single_Line_Field(field)) && \
182 (((field)->dcols == (field)->cols) && \
183 ((field)->opts & O_STATIC)) )
185 /* Logic to determine whether or not a dynamic field may still grow */
186 #define Growable(field) ((field)->status & _MAY_GROW)
188 /* Macro to set the attributes for a fields window */
189 #define Set_Field_Window_Attributes(field,win) \
190 ( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
191 wattrset((win),(field)->fore) )
193 /* Logic to decide whether or not a field really appears on the form */
194 #define Field_Really_Appears(field) \
196 (field->form->status & _POSTED) &&\
197 (field->opts & O_VISIBLE) &&\
198 (field->page == field->form->curpage))
200 /* Logic to determine whether or not we are on the first position in the
202 #define First_Position_In_Current_Field(form) \
203 (((form)->currow==0) && ((form)->curcol==0))
205 #define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
206 #define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
208 /*----------------------------------------------------------------------------
210 --------------------------------------------------------------------------*/
211 static FIELD_CELL myBLANK = BLANK;
212 static FIELD_CELL myZEROS;
216 check_pos(FORM *form, int lineno)
222 getyx(form->w, y, x);
223 if (y != form->currow || x != form->curcol)
225 T(("CHECKPOS %s@%d have position %d,%d vs want %d,%d",
228 form->currow, form->curcol));
232 #define CHECKPOS(form) check_pos(form, __LINE__)
234 #define CHECKPOS(form) /* nothing */
237 /*----------------------------------------------------------------------------
238 Wide-character special functions
239 --------------------------------------------------------------------------*/
240 #if USE_WIDEC_SUPPORT
243 wins_wchnstr(WINDOW *w, cchar_t *s, int n)
251 if ((code = wins_wch(w, s++)) != OK)
253 if ((code = wmove(w, y, x + 1)) != OK)
259 /* win_wchnstr is inconsistent with winnstr, since it returns OK rather than
260 * the number of items transferred.
263 fix_wchnstr(WINDOW *w, cchar_t *s, int n)
265 win_wchnstr(w, s, n);
270 * Returns the column of the base of the given cell.
273 cell_base(WINDOW *win, int y, int x)
277 while (LEGALYX(win, y, x))
279 cchar_t *data = &(win->_line[y].text[x]);
281 if (isWidecBase(CHDEREF(data)) || !isWidecExt(CHDEREF(data)))
292 * Returns the number of columns needed for the given cell in a window.
295 cell_width(WINDOW *win, int y, int x)
299 if (LEGALYX(win, y, x))
301 cchar_t *data = &(win->_line[y].text[x]);
303 if (isWidecExt(CHDEREF(data)))
305 /* recur, providing the number of columns to the next character */
306 result = cell_width(win, y, x - 1);
310 result = wcwidth(CharOf(CHDEREF(data)));
317 * There is no wide-character function such as wdel_wch(), so we must find
318 * all of the cells that comprise a multi-column character and delete them
322 delete_char(FORM *form)
324 int cells = cell_width(form->w, form->currow, form->curcol);
326 form->curcol = cell_base(form->w, form->currow, form->curcol);
327 wmove(form->w, form->currow, form->curcol);
333 #define DeleteChar(form) delete_char(form)
335 #define DeleteChar(form) \
336 wmove((form)->w, (form)->currow, (form)->curcol), \
340 /*---------------------------------------------------------------------------
341 | Facility : libnform
342 | Function : static char *Get_Start_Of_Data(char * buf, int blen)
344 | Description : Return pointer to first non-blank position in buffer.
345 | If buffer is empty return pointer to buffer itself.
347 | Return Values : Pointer to first non-blank position in buffer
348 +--------------------------------------------------------------------------*/
349 NCURSES_INLINE static FIELD_CELL *
350 Get_Start_Of_Data(FIELD_CELL *buf, int blen)
353 FIELD_CELL *end = &buf[blen];
355 assert(buf && blen >= 0);
356 while ((p < end) && ISBLANK(*p))
358 return ((p == end) ? buf : p);
361 /*---------------------------------------------------------------------------
362 | Facility : libnform
363 | Function : static char *After_End_Of_Data(char * buf, int blen)
365 | Description : Return pointer after last non-blank position in buffer.
366 | If buffer is empty, return pointer to buffer itself.
368 | Return Values : Pointer to position after last non-blank position in
370 +--------------------------------------------------------------------------*/
371 NCURSES_INLINE static FIELD_CELL *
372 After_End_Of_Data(FIELD_CELL *buf, int blen)
374 FIELD_CELL *p = &buf[blen];
376 assert(buf && blen >= 0);
377 while ((p > buf) && ISBLANK(p[-1]))
382 /*---------------------------------------------------------------------------
383 | Facility : libnform
384 | Function : static char *Get_First_Whitespace_Character(
385 | char * buf, int blen)
387 | Description : Position to the first whitespace character.
389 | Return Values : Pointer to first whitespace character in buffer.
390 +--------------------------------------------------------------------------*/
391 NCURSES_INLINE static FIELD_CELL *
392 Get_First_Whitespace_Character(FIELD_CELL *buf, int blen)
395 FIELD_CELL *end = &p[blen];
397 assert(buf && blen >= 0);
398 while ((p < end) && !ISBLANK(*p))
400 return ((p == end) ? buf : p);
403 /*---------------------------------------------------------------------------
404 | Facility : libnform
405 | Function : static char *After_Last_Whitespace_Character(
406 | char * buf, int blen)
408 | Description : Get the position after the last whitespace character.
410 | Return Values : Pointer to position after last whitespace character in
412 +--------------------------------------------------------------------------*/
413 NCURSES_INLINE static FIELD_CELL *
414 After_Last_Whitespace_Character(FIELD_CELL *buf, int blen)
416 FIELD_CELL *p = &buf[blen];
418 assert(buf && blen >= 0);
419 while ((p > buf) && !ISBLANK(p[-1]))
424 /* Set this to 1 to use the div_t version. This is a good idea if your
425 compiler has an intrinsic div() support. Unfortunately GNU-C has it
427 N.B.: This only works if form->curcol follows immediately form->currow
428 and both are of type int.
430 #define USE_DIV_T (0)
432 /*---------------------------------------------------------------------------
433 | Facility : libnform
434 | Function : static void Adjust_Cursor_Position(
435 | FORM * form, const char * pos)
437 | Description : Set current row and column of the form to values
438 | corresponding to the buffer position.
441 +--------------------------------------------------------------------------*/
442 NCURSES_INLINE static void
443 Adjust_Cursor_Position(FORM *form, const FIELD_CELL *pos)
448 field = form->current;
449 assert(pos >= field->buf && field->dcols > 0);
450 idx = (int)(pos - field->buf);
452 *((div_t *) & (form->currow)) = div(idx, field->dcols);
454 form->currow = idx / field->dcols;
455 form->curcol = idx - field->cols * form->currow;
457 if (field->drows < form->currow)
461 /*---------------------------------------------------------------------------
462 | Facility : libnform
463 | Function : static void Buffer_To_Window(
464 | const FIELD * field,
467 | Description : Copy the buffer to the window. If it is a multi-line
468 | field, the buffer is split to the lines of the
469 | window without any editing.
472 +--------------------------------------------------------------------------*/
474 Buffer_To_Window(const FIELD *field, WINDOW *win)
482 assert(win && field);
485 width = getmaxx(win);
486 height = getmaxy(win);
488 for (row = 0, pBuffer = field->buf;
490 row++, pBuffer += width)
492 if ((len = (int)(After_End_Of_Data(pBuffer, width) - pBuffer)) > 0)
495 myADDNSTR(win, pBuffer, len);
501 /*---------------------------------------------------------------------------
502 | Facility : libnform
503 | Function : static void Window_To_Buffer(
507 | Description : Copy the content of the window into the buffer.
508 | The multiple lines of a window are simply
509 | concatenated into the buffer. Pad characters in
510 | the window will be replaced by blanks in the buffer.
513 +--------------------------------------------------------------------------*/
515 Window_To_Buffer(WINDOW *win, FIELD *field)
522 assert(win && field && field->buf);
526 height = getmaxy(win);
528 for (row = 0; (row < height) && (row < field->drows); row++)
531 len += myINNSTR(win, p + len, field->dcols);
535 /* replace visual padding character by blanks in buffer */
540 for (i = 0; i < len; i++, p++)
542 if ((unsigned long)CharOf(*p) == ChCharOf(pad)
543 #if USE_WIDEC_SUPPORT
552 /*---------------------------------------------------------------------------
553 | Facility : libnform
554 | Function : static void Synchronize_Buffer(FORM * form)
556 | Description : If there was a change, copy the content of the
557 | window into the buffer, so the buffer is synchronized
558 | with the windows content. We have to indicate that the
559 | buffer needs validation due to the change.
562 +--------------------------------------------------------------------------*/
563 NCURSES_INLINE static void
564 Synchronize_Buffer(FORM *form)
566 if (form->status & _WINDOW_MODIFIED)
568 form->status &= ~_WINDOW_MODIFIED;
569 form->status |= _FCHECK_REQUIRED;
570 Window_To_Buffer(form->w, form->current);
571 wmove(form->w, form->currow, form->curcol);
575 /*---------------------------------------------------------------------------
576 | Facility : libnform
577 | Function : static bool Field_Grown( FIELD *field, int amount)
579 | Description : This function is called for growable dynamic fields
580 | only. It has to increase the buffers and to allocate
581 | a new window for this field.
582 | This function has the side effect to set a new
583 | field-buffer pointer, the dcols and drows values
584 | as well as a new current Window for the field.
586 | Return Values : TRUE - field successfully increased
587 | FALSE - there was some error
588 +--------------------------------------------------------------------------*/
590 Field_Grown(FIELD *field, int amount)
594 if (field && Growable(field))
596 bool single_line_field = Single_Line_Field(field);
597 int old_buflen = Buffer_Length(field);
599 int old_dcols = field->dcols;
600 int old_drows = field->drows;
601 FIELD_CELL *oldbuf = field->buf;
605 FORM *form = field->form;
606 bool need_visual_update = ((form != (FORM *)0) &&
607 (form->status & _POSTED) &&
608 (form->current == field));
610 if (need_visual_update)
611 Synchronize_Buffer(form);
613 if (single_line_field)
615 growth = field->cols * amount;
617 growth = Minimum(field->maxgrow - field->dcols, growth);
618 field->dcols += growth;
619 if (field->dcols == field->maxgrow)
620 field->status &= ~_MAY_GROW;
624 growth = (field->rows + field->nrow) * amount;
626 growth = Minimum(field->maxgrow - field->drows, growth);
627 field->drows += growth;
628 if (field->drows == field->maxgrow)
629 field->status &= ~_MAY_GROW;
631 /* drows, dcols changed, so we get really the new buffer length */
632 new_buflen = Buffer_Length(field);
633 newbuf = (FIELD_CELL *)malloc(Total_Buffer_Size(field));
636 /* restore to previous state */
637 field->dcols = old_dcols;
638 field->drows = old_drows;
639 if ((single_line_field && (field->dcols != field->maxgrow)) ||
640 (!single_line_field && (field->drows != field->maxgrow)))
641 field->status |= _MAY_GROW;
645 /* Copy all the buffers. This is the reason why we can't just use
652 result = TRUE; /* allow sharing of recovery on failure */
655 for (i = 0; i <= field->nbuf; i++)
657 new_bp = Address_Of_Nth_Buffer(field, i);
658 old_bp = oldbuf + i * (1 + old_buflen);
659 for (j = 0; j < old_buflen; ++j)
660 new_bp[j] = old_bp[j];
661 while (j < new_buflen)
662 new_bp[j++] = myBLANK;
663 new_bp[new_buflen] = myZEROS;
666 #if USE_WIDEC_SUPPORT
667 if (wresize(field->working, 1, Buffer_Length(field) + 1) == ERR)
671 if (need_visual_update && result)
673 WINDOW *new_window = newpad(field->drows, field->dcols);
677 assert(form != (FORM *)0);
680 form->w = new_window;
681 Set_Field_Window_Attributes(field, form->w);
683 Buffer_To_Window(field, form->w);
685 wmove(form->w, form->currow, form->curcol);
694 /* reflect changes in linked fields */
695 if (field != field->link)
699 for (linked_field = field->link;
700 linked_field != field;
701 linked_field = linked_field->link)
703 linked_field->buf = field->buf;
704 linked_field->drows = field->drows;
705 linked_field->dcols = field->dcols;
711 /* restore old state */
712 field->dcols = old_dcols;
713 field->drows = old_drows;
715 if ((single_line_field &&
716 (field->dcols != field->maxgrow)) ||
717 (!single_line_field &&
718 (field->drows != field->maxgrow)))
719 field->status |= _MAY_GROW;
727 /*---------------------------------------------------------------------------
728 | Facility : libnform
729 | Function : int _nc_Position_Form_Cursor(FORM * form)
731 | Description : Position the cursor in the window for the current
732 | field to be in sync. with the currow and curcol
735 | Return Values : E_OK - success
736 | E_BAD_ARGUMENT - invalid form pointer
737 | E_SYSTEM_ERROR - form has no current field or
739 +--------------------------------------------------------------------------*/
741 _nc_Position_Form_Cursor(FORM *form)
747 return (E_BAD_ARGUMENT);
749 if (!form->w || !form->current)
750 return (E_SYSTEM_ERROR);
752 field = form->current;
753 formwin = Get_Form_Window(form);
755 wmove(form->w, form->currow, form->curcol);
756 if (Has_Invisible_Parts(field))
758 /* in this case fieldwin isn't derived from formwin, so we have
759 to move the cursor in formwin by hand... */
761 field->frow + form->currow - form->toprow,
762 field->fcol + form->curcol - form->begincol);
770 /*---------------------------------------------------------------------------
771 | Facility : libnform
772 | Function : int _nc_Refresh_Current_Field(FORM * form)
774 | Description : Propagate the changes in the fields window to the
775 | window of the form.
777 | Return Values : E_OK - on success
778 | E_BAD_ARGUMENT - invalid form pointer
779 | E_SYSTEM_ERROR - general error
780 +--------------------------------------------------------------------------*/
782 _nc_Refresh_Current_Field(FORM *form)
787 T((T_CALLED("_nc_Refresh_Current_Field(%p)"), form));
790 RETURN(E_BAD_ARGUMENT);
792 if (!form->w || !form->current)
793 RETURN(E_SYSTEM_ERROR);
795 field = form->current;
796 formwin = Get_Form_Window(form);
798 if (field->opts & O_PUBLIC)
800 if (Is_Scroll_Field(field))
802 /* Again, in this case the fieldwin isn't derived from formwin,
803 so we have to perform a copy operation. */
804 if (Single_Line_Field(field))
806 /* horizontal scrolling */
807 if (form->curcol < form->begincol)
808 form->begincol = form->curcol;
811 if (form->curcol >= (form->begincol + field->cols))
812 form->begincol = form->curcol - field->cols + 1;
821 field->cols + field->fcol - 1,
826 /* A multi-line, i.e. vertical scrolling field */
827 int row_after_bottom, first_modified_row, first_unmodified_row;
829 if (field->drows > field->rows)
831 row_after_bottom = form->toprow + field->rows;
832 if (form->currow < form->toprow)
834 form->toprow = form->currow;
835 field->status |= _NEWTOP;
837 if (form->currow >= row_after_bottom)
839 form->toprow = form->currow - field->rows + 1;
840 field->status |= _NEWTOP;
842 if (field->status & _NEWTOP)
844 /* means we have to copy whole range */
845 first_modified_row = form->toprow;
846 first_unmodified_row = first_modified_row + field->rows;
847 field->status &= ~_NEWTOP;
851 /* we try to optimize : finding the range of touched
853 first_modified_row = form->toprow;
854 while (first_modified_row < row_after_bottom)
856 if (is_linetouched(form->w, first_modified_row))
858 first_modified_row++;
860 first_unmodified_row = first_modified_row;
861 while (first_unmodified_row < row_after_bottom)
863 if (!is_linetouched(form->w, first_unmodified_row))
865 first_unmodified_row++;
871 first_modified_row = form->toprow;
872 first_unmodified_row = first_modified_row + field->rows;
874 if (first_unmodified_row != first_modified_row)
879 field->frow + first_modified_row - form->toprow,
881 field->frow + first_unmodified_row - form->toprow - 1,
882 field->cols + field->fcol - 1,
889 /* if the field-window is simply a derived window, i.e. contains no
890 * invisible parts, the whole thing is trivial
896 returnCode(_nc_Position_Form_Cursor(form));
899 /*---------------------------------------------------------------------------
900 | Facility : libnform
901 | Function : static void Perform_Justification(
905 | Description : Output field with requested justification
908 +--------------------------------------------------------------------------*/
910 Perform_Justification(FIELD *field, WINDOW *win)
916 bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
917 len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
921 assert(win && (field->drows == 1) && (field->dcols == field->cols));
928 col = (field->cols - len) / 2;
931 col = field->cols - len;
938 myADDNSTR(win, bp, len);
942 /*---------------------------------------------------------------------------
943 | Facility : libnform
944 | Function : static void Undo_Justification(
948 | Description : Display field without any justification, i.e.
952 +--------------------------------------------------------------------------*/
954 Undo_Justification(FIELD *field, WINDOW *win)
959 bp = Get_Start_Of_Data(field->buf, Buffer_Length(field));
960 len = (int)(After_End_Of_Data(field->buf, Buffer_Length(field)) - bp);
966 myADDNSTR(win, bp, len);
970 /*---------------------------------------------------------------------------
971 | Facility : libnform
972 | Function : static bool Check_Char(
975 | TypeArgument *argp)
977 | Description : Perform a single character check for character ch
978 | according to the fieldtype instance.
980 | Return Values : TRUE - Character is valid
981 | FALSE - Character is invalid
982 +--------------------------------------------------------------------------*/
984 Check_Char(FIELDTYPE *typ, int ch, TypeArgument *argp)
988 if (typ->status & _LINKED_TYPE)
992 Check_Char(typ->left, ch, argp->left) ||
993 Check_Char(typ->right, ch, argp->right));
998 return typ->ccheck(ch, (void *)argp);
1001 return (!iscntrl(UChar(ch)) ? TRUE : FALSE);
1004 /*---------------------------------------------------------------------------
1005 | Facility : libnform
1006 | Function : static int Display_Or_Erase_Field(
1010 | Description : Create a subwindow for the field and display the
1011 | buffer contents (apply justification if required)
1012 | or simply erase the field.
1014 | Return Values : E_OK - on success
1015 | E_SYSTEM_ERROR - some error (typical no memory)
1016 +--------------------------------------------------------------------------*/
1018 Display_Or_Erase_Field(FIELD *field, bool bEraseFlag)
1024 return E_SYSTEM_ERROR;
1026 fwin = Get_Form_Window(field->form);
1028 field->rows, field->cols, field->frow, field->fcol);
1031 return E_SYSTEM_ERROR;
1034 if (field->opts & O_VISIBLE)
1035 Set_Field_Window_Attributes(field, win);
1037 wattrset(win, WINDOW_ATTRS(fwin));
1043 if (field->opts & O_PUBLIC)
1045 if (Justification_Allowed(field))
1046 Perform_Justification(field, win);
1048 Buffer_To_Window(field, win);
1050 field->status &= ~_NEWTOP;
1057 /* Macros to preset the bEraseFlag */
1058 #define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
1059 #define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
1061 /*---------------------------------------------------------------------------
1062 | Facility : libnform
1063 | Function : static int Synchronize_Field(FIELD * field)
1065 | Description : Synchronize the windows content with the value in
1068 | Return Values : E_OK - success
1069 | E_BAD_ARGUMENT - invalid field pointer
1070 | E_SYSTEM_ERROR - some severe basic error
1071 +--------------------------------------------------------------------------*/
1073 Synchronize_Field(FIELD *field)
1079 return (E_BAD_ARGUMENT);
1081 if (((form = field->form) != (FORM *)0)
1082 && Field_Really_Appears(field))
1084 if (field == form->current)
1086 form->currow = form->curcol = form->toprow = form->begincol = 0;
1089 if ((field->opts & O_PUBLIC) && Justification_Allowed(field))
1090 Undo_Justification(field, form->w);
1092 Buffer_To_Window(field, form->w);
1094 field->status |= _NEWTOP;
1095 res = _nc_Refresh_Current_Field(form);
1098 res = Display_Field(field);
1100 field->status |= _CHANGED;
1104 /*---------------------------------------------------------------------------
1105 | Facility : libnform
1106 | Function : static int Synchronize_Linked_Fields(FIELD * field)
1108 | Description : Propagate the Synchronize_Field function to all linked
1109 | fields. The first error that occurs in the sequence
1110 | of updates is the return value.
1112 | Return Values : E_OK - success
1113 | E_BAD_ARGUMENT - invalid field pointer
1114 | E_SYSTEM_ERROR - some severe basic error
1115 +--------------------------------------------------------------------------*/
1117 Synchronize_Linked_Fields(FIELD *field)
1119 FIELD *linked_field;
1124 return (E_BAD_ARGUMENT);
1127 return (E_SYSTEM_ERROR);
1129 for (linked_field = field->link;
1130 linked_field != field;
1131 linked_field = linked_field->link)
1133 if (((syncres = Synchronize_Field(linked_field)) != E_OK) &&
1140 /*---------------------------------------------------------------------------
1141 | Facility : libnform
1142 | Function : int _nc_Synchronize_Attributes(FIELD * field)
1144 | Description : If a fields visual attributes have changed, this
1145 | routine is called to propagate those changes to the
1148 | Return Values : E_OK - success
1149 | E_BAD_ARGUMENT - invalid field pointer
1150 | E_SYSTEM_ERROR - some severe basic error
1151 +--------------------------------------------------------------------------*/
1153 _nc_Synchronize_Attributes(FIELD *field)
1159 T((T_CALLED("_nc_Synchronize_Attributes(%p)"), field));
1162 returnCode(E_BAD_ARGUMENT);
1164 CHECKPOS(field->form);
1165 if (((form = field->form) != (FORM *)0)
1166 && Field_Really_Appears(field))
1168 if (form->current == field)
1170 Synchronize_Buffer(form);
1171 Set_Field_Window_Attributes(field, form->w);
1173 wmove(form->w, form->currow, form->curcol);
1175 if (field->opts & O_PUBLIC)
1177 if (Justification_Allowed(field))
1178 Undo_Justification(field, form->w);
1180 Buffer_To_Window(field, form->w);
1184 formwin = Get_Form_Window(form);
1185 copywin(form->w, formwin,
1187 field->frow, field->fcol,
1188 field->rows - 1, field->cols - 1, 0);
1190 Buffer_To_Window(field, form->w);
1191 field->status |= _NEWTOP; /* fake refresh to paint all */
1192 _nc_Refresh_Current_Field(form);
1197 res = Display_Field(field);
1204 /*---------------------------------------------------------------------------
1205 | Facility : libnform
1206 | Function : int _nc_Synchronize_Options(FIELD * field,
1207 | Field_Options newopts)
1209 | Description : If a fields options have changed, this routine is
1210 | called to propagate these changes to the screen and
1211 | to really change the behavior of the field.
1213 | Return Values : E_OK - success
1214 | E_BAD_ARGUMENT - invalid field pointer
1215 | E_CURRENT - field is the current one
1216 | E_SYSTEM_ERROR - some severe basic error
1217 +--------------------------------------------------------------------------*/
1219 _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
1221 Field_Options oldopts;
1222 Field_Options changed_opts;
1226 T((T_CALLED("_nc_Synchronize_Options(%p,%#x)"), field, newopts));
1229 returnCode(E_BAD_ARGUMENT);
1231 oldopts = field->opts;
1232 changed_opts = oldopts ^ newopts;
1233 field->opts = newopts;
1238 if (form->current == field)
1240 field->opts = oldopts;
1241 returnCode(E_CURRENT);
1244 if (form->status & _POSTED)
1246 if ((form->curpage == field->page))
1248 if (changed_opts & O_VISIBLE)
1250 if (newopts & O_VISIBLE)
1251 res = Display_Field(field);
1253 res = Erase_Field(field);
1257 if ((changed_opts & O_PUBLIC) &&
1258 (newopts & O_VISIBLE))
1259 res = Display_Field(field);
1265 if (changed_opts & O_STATIC)
1267 bool single_line_field = Single_Line_Field(field);
1270 if (newopts & O_STATIC)
1272 /* the field becomes now static */
1273 field->status &= ~_MAY_GROW;
1274 /* if actually we have no hidden columns, justification may
1276 if (single_line_field &&
1277 (field->cols == field->dcols) &&
1278 (field->just != NO_JUSTIFICATION) &&
1279 Field_Really_Appears(field))
1281 res2 = Display_Field(field);
1286 /* field is no longer static */
1287 if ((field->maxgrow == 0) ||
1288 (single_line_field && (field->dcols < field->maxgrow)) ||
1289 (!single_line_field && (field->drows < field->maxgrow)))
1291 field->status |= _MAY_GROW;
1292 /* a field with justification now changes its behavior,
1293 so we must redisplay it */
1294 if (single_line_field &&
1295 (field->just != NO_JUSTIFICATION) &&
1296 Field_Really_Appears(field))
1298 res2 = Display_Field(field);
1309 /*---------------------------------------------------------------------------
1310 | Facility : libnform
1311 | Function : int _nc_Set_Current_Field(FORM * form,
1314 | Description : Make the newfield the new current field.
1316 | Return Values : E_OK - success
1317 | E_BAD_ARGUMENT - invalid form or field pointer
1318 | E_SYSTEM_ERROR - some severe basic error
1319 | E_NOT_CONNECTED - no fields are connected to the form
1320 +--------------------------------------------------------------------------*/
1322 _nc_Set_Current_Field(FORM *form, FIELD *newfield)
1327 T((T_CALLED("_nc_Set_Current_Field(%p,%p)"), form, newfield));
1329 if (!form || !newfield || !form->current || (newfield->form != form))
1330 returnCode(E_BAD_ARGUMENT);
1332 if ((form->status & _IN_DRIVER))
1333 returnCode(E_BAD_STATE);
1336 returnCode(E_NOT_CONNECTED);
1338 field = form->current;
1340 if ((field != newfield) ||
1341 !(form->status & _POSTED))
1344 (field->opts & O_VISIBLE) &&
1345 (field->form->curpage == field->page))
1347 _nc_Refresh_Current_Field(form);
1348 if (field->opts & O_PUBLIC)
1350 if (field->drows > field->rows)
1352 if (form->toprow == 0)
1353 field->status &= ~_NEWTOP;
1355 field->status |= _NEWTOP;
1359 if (Justification_Allowed(field))
1361 Window_To_Buffer(form->w, field);
1363 Perform_Justification(field, form->w);
1369 form->w = (WINDOW *)0;
1374 if (Has_Invisible_Parts(field))
1375 new_window = newpad(field->drows, field->dcols);
1377 new_window = derwin(Get_Form_Window(form),
1378 field->rows, field->cols, field->frow, field->fcol);
1381 returnCode(E_SYSTEM_ERROR);
1383 form->current = field;
1387 form->w = new_window;
1389 form->status &= ~_WINDOW_MODIFIED;
1390 Set_Field_Window_Attributes(field, form->w);
1392 if (Has_Invisible_Parts(field))
1395 Buffer_To_Window(field, form->w);
1399 if (Justification_Allowed(field))
1402 Undo_Justification(field, form->w);
1407 untouchwin(form->w);
1410 form->currow = form->curcol = form->toprow = form->begincol = 0;
1414 /*----------------------------------------------------------------------------
1415 Intra-Field Navigation routines
1416 --------------------------------------------------------------------------*/
1418 /*---------------------------------------------------------------------------
1419 | Facility : libnform
1420 | Function : static int IFN_Next_Character(FORM * form)
1422 | Description : Move to the next character in the field. In a multi-line
1423 | field this wraps at the end of the line.
1425 | Return Values : E_OK - success
1426 | E_REQUEST_DENIED - at the rightmost position
1427 +--------------------------------------------------------------------------*/
1429 IFN_Next_Character(FORM *form)
1431 FIELD *field = form->current;
1432 int step = myWCWIDTH(form->w, form->currow, form->curcol);
1434 T((T_CALLED("IFN_Next_Character(%p)"), form));
1435 if ((form->curcol += step) == field->dcols)
1437 if ((++(form->currow)) == field->drows)
1439 #if GROW_IF_NAVIGATE
1440 if (!Single_Line_Field(field) && Field_Grown(field, 1))
1447 #if GROW_IF_NAVIGATE
1448 if (Single_Line_Field(field) && Field_Grown(field, 1))
1451 form->curcol -= step;
1452 returnCode(E_REQUEST_DENIED);
1459 /*---------------------------------------------------------------------------
1460 | Facility : libnform
1461 | Function : static int IFN_Previous_Character(FORM * form)
1463 | Description : Move to the previous character in the field. In a
1464 | multi-line field this wraps and the beginning of the
1467 | Return Values : E_OK - success
1468 | E_REQUEST_DENIED - at the leftmost position
1469 +--------------------------------------------------------------------------*/
1471 IFN_Previous_Character(FORM *form)
1473 int amount = myWCWIDTH(form->w, form->currow, form->curcol - 1);
1474 int oldcol = form->curcol;
1476 T((T_CALLED("IFN_Previous_Character(%p)"), form));
1477 if ((form->curcol -= amount) < 0)
1479 if ((--(form->currow)) < 0)
1482 form->curcol = oldcol;
1483 returnCode(E_REQUEST_DENIED);
1485 form->curcol = form->current->dcols - 1;
1490 /*---------------------------------------------------------------------------
1491 | Facility : libnform
1492 | Function : static int IFN_Next_Line(FORM * form)
1494 | Description : Move to the beginning of the next line in the field
1496 | Return Values : E_OK - success
1497 | E_REQUEST_DENIED - at the last line
1498 +--------------------------------------------------------------------------*/
1500 IFN_Next_Line(FORM *form)
1502 FIELD *field = form->current;
1504 T((T_CALLED("IFN_Next_Line(%p)"), form));
1505 if ((++(form->currow)) == field->drows)
1507 #if GROW_IF_NAVIGATE
1508 if (!Single_Line_Field(field) && Field_Grown(field, 1))
1512 returnCode(E_REQUEST_DENIED);
1518 /*---------------------------------------------------------------------------
1519 | Facility : libnform
1520 | Function : static int IFN_Previous_Line(FORM * form)
1522 | Description : Move to the beginning of the previous line in the field
1524 | Return Values : E_OK - success
1525 | E_REQUEST_DENIED - at the first line
1526 +--------------------------------------------------------------------------*/
1528 IFN_Previous_Line(FORM *form)
1530 T((T_CALLED("IFN_Previous_Line(%p)"), form));
1531 if ((--(form->currow)) < 0)
1534 returnCode(E_REQUEST_DENIED);
1540 /*---------------------------------------------------------------------------
1541 | Facility : libnform
1542 | Function : static int IFN_Next_Word(FORM * form)
1544 | Description : Move to the beginning of the next word in the field.
1546 | Return Values : E_OK - success
1547 | E_REQUEST_DENIED - there is no next word
1548 +--------------------------------------------------------------------------*/
1550 IFN_Next_Word(FORM *form)
1552 FIELD *field = form->current;
1553 FIELD_CELL *bp = Address_Of_Current_Position_In_Buffer(form);
1557 T((T_CALLED("IFN_Next_Word(%p)"), form));
1559 /* We really need access to the data, so we have to synchronize */
1560 Synchronize_Buffer(form);
1562 /* Go to the first whitespace after the current position (including
1563 current position). This is then the starting point to look for the
1564 next non-blank data */
1565 s = Get_First_Whitespace_Character(bp, Buffer_Length(field) -
1566 (int)(bp - field->buf));
1568 /* Find the start of the next word */
1569 t = Get_Start_Of_Data(s, Buffer_Length(field) -
1570 (int)(s - field->buf));
1571 #if !FRIENDLY_PREV_NEXT_WORD
1573 returnCode(E_REQUEST_DENIED);
1577 Adjust_Cursor_Position(form, t);
1582 /*---------------------------------------------------------------------------
1583 | Facility : libnform
1584 | Function : static int IFN_Previous_Word(FORM * form)
1586 | Description : Move to the beginning of the previous word in the field.
1588 | Return Values : E_OK - success
1589 | E_REQUEST_DENIED - there is no previous word
1590 +--------------------------------------------------------------------------*/
1592 IFN_Previous_Word(FORM *form)
1594 FIELD *field = form->current;
1595 FIELD_CELL *bp = Address_Of_Current_Position_In_Buffer(form);
1600 T((T_CALLED("IFN_Previous_Word(%p)"), form));
1602 /* We really need access to the data, so we have to synchronize */
1603 Synchronize_Buffer(form);
1605 s = After_End_Of_Data(field->buf, (int)(bp - field->buf));
1606 /* s points now right after the last non-blank in the buffer before bp.
1607 If bp was in a word, s equals bp. In this case we must find the last
1608 whitespace in the buffer before bp and repeat the game to really find
1609 the previous word! */
1613 /* And next call now goes backward to look for the last whitespace
1614 before that, pointing right after this, so it points to the begin
1615 of the previous word.
1617 t = After_Last_Whitespace_Character(field->buf, (int)(s - field->buf));
1618 #if !FRIENDLY_PREV_NEXT_WORD
1620 returnCode(E_REQUEST_DENIED);
1624 /* and do it again, replacing bp by t */
1625 s = After_End_Of_Data(field->buf, (int)(t - field->buf));
1626 t = After_Last_Whitespace_Character(field->buf, (int)(s - field->buf));
1627 #if !FRIENDLY_PREV_NEXT_WORD
1629 returnCode(E_REQUEST_DENIED);
1632 Adjust_Cursor_Position(form, t);
1636 /*---------------------------------------------------------------------------
1637 | Facility : libnform
1638 | Function : static int IFN_Beginning_Of_Field(FORM * form)
1640 | Description : Place the cursor at the first non-pad character in
1643 | Return Values : E_OK - success
1644 +--------------------------------------------------------------------------*/
1646 IFN_Beginning_Of_Field(FORM *form)
1648 FIELD *field = form->current;
1650 T((T_CALLED("IFN_Beginning_Of_Field(%p)"), form));
1651 Synchronize_Buffer(form);
1652 Adjust_Cursor_Position(form,
1653 Get_Start_Of_Data(field->buf, Buffer_Length(field)));
1657 /*---------------------------------------------------------------------------
1658 | Facility : libnform
1659 | Function : static int IFN_End_Of_Field(FORM * form)
1661 | Description : Place the cursor after the last non-pad character in
1662 | the field. If the field occupies the last position in
1663 | the buffer, the cursor is positioned on the last
1666 | Return Values : E_OK - success
1667 +--------------------------------------------------------------------------*/
1669 IFN_End_Of_Field(FORM *form)
1671 FIELD *field = form->current;
1674 T((T_CALLED("IFN_End_Of_Field(%p)"), form));
1675 Synchronize_Buffer(form);
1676 pos = After_End_Of_Data(field->buf, Buffer_Length(field));
1677 if (pos == (field->buf + Buffer_Length(field)))
1679 Adjust_Cursor_Position(form, pos);
1683 /*---------------------------------------------------------------------------
1684 | Facility : libnform
1685 | Function : static int IFN_Beginning_Of_Line(FORM * form)
1687 | Description : Place the cursor on the first non-pad character in
1688 | the current line of the field.
1690 | Return Values : E_OK - success
1691 +--------------------------------------------------------------------------*/
1693 IFN_Beginning_Of_Line(FORM *form)
1695 FIELD *field = form->current;
1697 T((T_CALLED("IFN_Beginning_Of_Line(%p)"), form));
1698 Synchronize_Buffer(form);
1699 Adjust_Cursor_Position(form,
1700 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1705 /*---------------------------------------------------------------------------
1706 | Facility : libnform
1707 | Function : static int IFN_End_Of_Line(FORM * form)
1709 | Description : Place the cursor after the last non-pad character in the
1710 | current line of the field. If the field occupies the
1711 | last column in the line, the cursor is positioned on the
1712 | last character of the line.
1714 | Return Values : E_OK - success
1715 +--------------------------------------------------------------------------*/
1717 IFN_End_Of_Line(FORM *form)
1719 FIELD *field = form->current;
1723 T((T_CALLED("IFN_End_Of_Line(%p)"), form));
1724 Synchronize_Buffer(form);
1725 bp = Address_Of_Current_Row_In_Buffer(form);
1726 pos = After_End_Of_Data(bp, field->dcols);
1727 if (pos == (bp + field->dcols))
1729 Adjust_Cursor_Position(form, pos);
1733 /*---------------------------------------------------------------------------
1734 | Facility : libnform
1735 | Function : static int IFN_Left_Character(FORM * form)
1737 | Description : Move one character to the left in the current line.
1738 | This doesn't cycle.
1740 | Return Values : E_OK - success
1741 | E_REQUEST_DENIED - already in first column
1742 +--------------------------------------------------------------------------*/
1744 IFN_Left_Character(FORM *form)
1746 int amount = myWCWIDTH(form->w, form->currow, form->curcol - 1);
1747 int oldcol = form->curcol;
1749 T((T_CALLED("IFN_Left_Character(%p)"), form));
1750 if ((form->curcol -= amount) < 0)
1752 form->curcol = oldcol;
1753 returnCode(E_REQUEST_DENIED);
1758 /*---------------------------------------------------------------------------
1759 | Facility : libnform
1760 | Function : static int IFN_Right_Character(FORM * form)
1762 | Description : Move one character to the right in the current line.
1763 | This doesn't cycle.
1765 | Return Values : E_OK - success
1766 | E_REQUEST_DENIED - already in last column
1767 +--------------------------------------------------------------------------*/
1769 IFN_Right_Character(FORM *form)
1771 int amount = myWCWIDTH(form->w, form->currow, form->curcol);
1772 int oldcol = form->curcol;
1774 T((T_CALLED("IFN_Right_Character(%p)"), form));
1775 if ((form->curcol += amount) >= form->current->dcols)
1777 #if GROW_IF_NAVIGATE
1778 FIELD *field = form->current;
1780 if (Single_Line_Field(field) && Field_Grown(field, 1))
1783 form->curcol = oldcol;
1784 returnCode(E_REQUEST_DENIED);
1789 /*---------------------------------------------------------------------------
1790 | Facility : libnform
1791 | Function : static int IFN_Up_Character(FORM * form)
1793 | Description : Move one line up. This doesn't cycle through the lines
1796 | Return Values : E_OK - success
1797 | E_REQUEST_DENIED - already in last column
1798 +--------------------------------------------------------------------------*/
1800 IFN_Up_Character(FORM *form)
1802 T((T_CALLED("IFN_Up_Character(%p)"), form));
1803 if ((--(form->currow)) < 0)
1806 returnCode(E_REQUEST_DENIED);
1811 /*---------------------------------------------------------------------------
1812 | Facility : libnform
1813 | Function : static int IFN_Down_Character(FORM * form)
1815 | Description : Move one line down. This doesn't cycle through the
1816 | lines of the field.
1818 | Return Values : E_OK - success
1819 | E_REQUEST_DENIED - already in last column
1820 +--------------------------------------------------------------------------*/
1822 IFN_Down_Character(FORM *form)
1824 FIELD *field = form->current;
1826 T((T_CALLED("IFN_Down_Character(%p)"), form));
1827 if ((++(form->currow)) == field->drows)
1829 #if GROW_IF_NAVIGATE
1830 if (!Single_Line_Field(field) && Field_Grown(field, 1))
1834 returnCode(E_REQUEST_DENIED);
1838 /*----------------------------------------------------------------------------
1839 END of Intra-Field Navigation routines
1840 --------------------------------------------------------------------------*/
1842 /*----------------------------------------------------------------------------
1843 Vertical scrolling helper routines
1844 --------------------------------------------------------------------------*/
1846 /*---------------------------------------------------------------------------
1847 | Facility : libnform
1848 | Function : static int VSC_Generic(FORM *form, int nlines)
1850 | Description : Scroll multi-line field forward (nlines>0) or
1851 | backward (nlines<0) this many lines.
1853 | Return Values : E_OK - success
1854 | E_REQUEST_DENIED - can't scroll
1855 +--------------------------------------------------------------------------*/
1857 VSC_Generic(FORM *form, int nlines)
1859 FIELD *field = form->current;
1860 int res = E_REQUEST_DENIED;
1861 int rows_to_go = (nlines > 0 ? nlines : -nlines);
1865 if ((rows_to_go + form->toprow) > (field->drows - field->rows))
1866 rows_to_go = (field->drows - field->rows - form->toprow);
1870 form->currow += rows_to_go;
1871 form->toprow += rows_to_go;
1877 if (rows_to_go > form->toprow)
1878 rows_to_go = form->toprow;
1882 form->currow -= rows_to_go;
1883 form->toprow -= rows_to_go;
1889 /*----------------------------------------------------------------------------
1890 End of Vertical scrolling helper routines
1891 --------------------------------------------------------------------------*/
1893 /*----------------------------------------------------------------------------
1894 Vertical scrolling routines
1895 --------------------------------------------------------------------------*/
1897 /*---------------------------------------------------------------------------
1898 | Facility : libnform
1899 | Function : static int Vertical_Scrolling(
1900 | int (* const fct) (FORM *),
1903 | Description : Performs the generic vertical scrolling routines.
1904 | This has to check for a multi-line field and to set
1905 | the _NEWTOP flag if scrolling really occurred.
1907 | Return Values : Propagated error code from low-level driver calls
1908 +--------------------------------------------------------------------------*/
1910 Vertical_Scrolling(int (*const fct) (FORM *), FORM *form)
1912 int res = E_REQUEST_DENIED;
1914 if (!Single_Line_Field(form->current))
1918 form->current->status |= _NEWTOP;
1923 /*---------------------------------------------------------------------------
1924 | Facility : libnform
1925 | Function : static int VSC_Scroll_Line_Forward(FORM * form)
1927 | Description : Scroll multi-line field forward a line
1929 | Return Values : E_OK - success
1930 | E_REQUEST_DENIED - no data ahead
1931 +--------------------------------------------------------------------------*/
1933 VSC_Scroll_Line_Forward(FORM *form)
1935 T((T_CALLED("VSC_Scroll_Line_Forward(%p)"), form));
1936 returnCode(VSC_Generic(form, 1));
1939 /*---------------------------------------------------------------------------
1940 | Facility : libnform
1941 | Function : static int VSC_Scroll_Line_Backward(FORM * form)
1943 | Description : Scroll multi-line field backward a line
1945 | Return Values : E_OK - success
1946 | E_REQUEST_DENIED - no data behind
1947 +--------------------------------------------------------------------------*/
1949 VSC_Scroll_Line_Backward(FORM *form)
1951 T((T_CALLED("VSC_Scroll_Line_Backward(%p)"), form));
1952 returnCode(VSC_Generic(form, -1));
1955 /*---------------------------------------------------------------------------
1956 | Facility : libnform
1957 | Function : static int VSC_Scroll_Page_Forward(FORM * form)
1959 | Description : Scroll a multi-line field forward a page
1961 | Return Values : E_OK - success
1962 | E_REQUEST_DENIED - no data ahead
1963 +--------------------------------------------------------------------------*/
1965 VSC_Scroll_Page_Forward(FORM *form)
1967 T((T_CALLED("VSC_Scroll_Page_Forward(%p)"), form));
1968 returnCode(VSC_Generic(form, form->current->rows));
1971 /*---------------------------------------------------------------------------
1972 | Facility : libnform
1973 | Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1975 | Description : Scroll a multi-line field forward half a page
1977 | Return Values : E_OK - success
1978 | E_REQUEST_DENIED - no data ahead
1979 +--------------------------------------------------------------------------*/
1981 VSC_Scroll_Half_Page_Forward(FORM *form)
1983 T((T_CALLED("VSC_Scroll_Half_Page_Forward(%p)"), form));
1984 returnCode(VSC_Generic(form, (form->current->rows + 1) / 2));
1987 /*---------------------------------------------------------------------------
1988 | Facility : libnform
1989 | Function : static int VSC_Scroll_Page_Backward(FORM * form)
1991 | Description : Scroll a multi-line field backward a page
1993 | Return Values : E_OK - success
1994 | E_REQUEST_DENIED - no data behind
1995 +--------------------------------------------------------------------------*/
1997 VSC_Scroll_Page_Backward(FORM *form)
1999 T((T_CALLED("VSC_Scroll_Page_Backward(%p)"), form));
2000 returnCode(VSC_Generic(form, -(form->current->rows)));
2003 /*---------------------------------------------------------------------------
2004 | Facility : libnform
2005 | Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
2007 | Description : Scroll a multi-line field backward half a page
2009 | Return Values : E_OK - success
2010 | E_REQUEST_DENIED - no data behind
2011 +--------------------------------------------------------------------------*/
2013 VSC_Scroll_Half_Page_Backward(FORM *form)
2015 T((T_CALLED("VSC_Scroll_Half_Page_Backward(%p)"), form));
2016 returnCode(VSC_Generic(form, -((form->current->rows + 1) / 2)));
2018 /*----------------------------------------------------------------------------
2019 End of Vertical scrolling routines
2020 --------------------------------------------------------------------------*/
2022 /*----------------------------------------------------------------------------
2023 Horizontal scrolling helper routines
2024 --------------------------------------------------------------------------*/
2026 /*---------------------------------------------------------------------------
2027 | Facility : libnform
2028 | Function : static int HSC_Generic(FORM *form, int ncolumns)
2030 | Description : Scroll single-line field forward (ncolumns>0) or
2031 | backward (ncolumns<0) this many columns.
2033 | Return Values : E_OK - success
2034 | E_REQUEST_DENIED - can't scroll
2035 +--------------------------------------------------------------------------*/
2037 HSC_Generic(FORM *form, int ncolumns)
2039 FIELD *field = form->current;
2040 int res = E_REQUEST_DENIED;
2041 int cols_to_go = (ncolumns > 0 ? ncolumns : -ncolumns);
2045 if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
2046 cols_to_go = field->dcols - field->cols - form->begincol;
2050 form->curcol += cols_to_go;
2051 form->begincol += cols_to_go;
2057 if (cols_to_go > form->begincol)
2058 cols_to_go = form->begincol;
2062 form->curcol -= cols_to_go;
2063 form->begincol -= cols_to_go;
2069 /*----------------------------------------------------------------------------
2070 End of Horizontal scrolling helper routines
2071 --------------------------------------------------------------------------*/
2073 /*----------------------------------------------------------------------------
2074 Horizontal scrolling routines
2075 --------------------------------------------------------------------------*/
2077 /*---------------------------------------------------------------------------
2078 | Facility : libnform
2079 | Function : static int Horizontal_Scrolling(
2080 | int (* const fct) (FORM *),
2083 | Description : Performs the generic horizontal scrolling routines.
2084 | This has to check for a single-line field.
2086 | Return Values : Propagated error code from low-level driver calls
2087 +--------------------------------------------------------------------------*/
2089 Horizontal_Scrolling(int (*const fct) (FORM *), FORM *form)
2091 if (Single_Line_Field(form->current))
2094 return (E_REQUEST_DENIED);
2097 /*---------------------------------------------------------------------------
2098 | Facility : libnform
2099 | Function : static int HSC_Scroll_Char_Forward(FORM * form)
2101 | Description : Scroll single-line field forward a character
2103 | Return Values : E_OK - success
2104 | E_REQUEST_DENIED - no data ahead
2105 +--------------------------------------------------------------------------*/
2107 HSC_Scroll_Char_Forward(FORM *form)
2109 T((T_CALLED("HSC_Scroll_Char_Forward(%p)"), form));
2110 returnCode(HSC_Generic(form, 1));
2113 /*---------------------------------------------------------------------------
2114 | Facility : libnform
2115 | Function : static int HSC_Scroll_Char_Backward(FORM * form)
2117 | Description : Scroll single-line field backward a character
2119 | Return Values : E_OK - success
2120 | E_REQUEST_DENIED - no data behind
2121 +--------------------------------------------------------------------------*/
2123 HSC_Scroll_Char_Backward(FORM *form)
2125 T((T_CALLED("HSC_Scroll_Char_Backward(%p)"), form));
2126 returnCode(HSC_Generic(form, -1));
2129 /*---------------------------------------------------------------------------
2130 | Facility : libnform
2131 | Function : static int HSC_Horizontal_Line_Forward(FORM* form)
2133 | Description : Scroll single-line field forward a line
2135 | Return Values : E_OK - success
2136 | E_REQUEST_DENIED - no data ahead
2137 +--------------------------------------------------------------------------*/
2139 HSC_Horizontal_Line_Forward(FORM *form)
2141 T((T_CALLED("HSC_Horizontal_Line_Forward(%p)"), form));
2142 returnCode(HSC_Generic(form, form->current->cols));
2145 /*---------------------------------------------------------------------------
2146 | Facility : libnform
2147 | Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
2149 | Description : Scroll single-line field forward half a line
2151 | Return Values : E_OK - success
2152 | E_REQUEST_DENIED - no data ahead
2153 +--------------------------------------------------------------------------*/
2155 HSC_Horizontal_Half_Line_Forward(FORM *form)
2157 T((T_CALLED("HSC_Horizontal_Half_Line_Forward(%p)"), form));
2158 returnCode(HSC_Generic(form, (form->current->cols + 1) / 2));
2161 /*---------------------------------------------------------------------------
2162 | Facility : libnform
2163 | Function : static int HSC_Horizontal_Line_Backward(FORM* form)
2165 | Description : Scroll single-line field backward a line
2167 | Return Values : E_OK - success
2168 | E_REQUEST_DENIED - no data behind
2169 +--------------------------------------------------------------------------*/
2171 HSC_Horizontal_Line_Backward(FORM *form)
2173 T((T_CALLED("HSC_Horizontal_Line_Backward(%p)"), form));
2174 returnCode(HSC_Generic(form, -(form->current->cols)));
2177 /*---------------------------------------------------------------------------
2178 | Facility : libnform
2179 | Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
2181 | Description : Scroll single-line field backward half a line
2183 | Return Values : E_OK - success
2184 | E_REQUEST_DENIED - no data behind
2185 +--------------------------------------------------------------------------*/
2187 HSC_Horizontal_Half_Line_Backward(FORM *form)
2189 T((T_CALLED("HSC_Horizontal_Half_Line_Backward(%p)"), form));
2190 returnCode(HSC_Generic(form, -((form->current->cols + 1) / 2)));
2193 /*----------------------------------------------------------------------------
2194 End of Horizontal scrolling routines
2195 --------------------------------------------------------------------------*/
2197 /*----------------------------------------------------------------------------
2198 Helper routines for Field Editing
2199 --------------------------------------------------------------------------*/
2201 /*---------------------------------------------------------------------------
2202 | Facility : libnform
2203 | Function : static bool Is_There_Room_For_A_Line(FORM * form)
2205 | Description : Check whether or not there is enough room in the
2206 | buffer to enter a whole line.
2208 | Return Values : TRUE - there is enough space
2209 | FALSE - there is not enough space
2210 +--------------------------------------------------------------------------*/
2211 NCURSES_INLINE static bool
2212 Is_There_Room_For_A_Line(FORM *form)
2214 FIELD *field = form->current;
2215 FIELD_CELL *begin_of_last_line, *s;
2217 Synchronize_Buffer(form);
2218 begin_of_last_line = Address_Of_Row_In_Buffer(field, (field->drows - 1));
2219 s = After_End_Of_Data(begin_of_last_line, field->dcols);
2220 return ((s == begin_of_last_line) ? TRUE : FALSE);
2223 /*---------------------------------------------------------------------------
2224 | Facility : libnform
2225 | Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
2227 | Description : Checks whether or not there is room for a new character
2228 | in the current line.
2230 | Return Values : TRUE - there is room
2231 | FALSE - there is not enough room (line full)
2232 +--------------------------------------------------------------------------*/
2233 NCURSES_INLINE static bool
2234 Is_There_Room_For_A_Char_In_Line(FORM *form)
2236 int last_char_in_line;
2238 wmove(form->w, form->currow, form->current->dcols - 1);
2239 last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
2240 wmove(form->w, form->currow, form->curcol);
2241 return (((last_char_in_line == form->current->pad) ||
2242 is_blank(last_char_in_line)) ? TRUE : FALSE);
2245 #define There_Is_No_Room_For_A_Char_In_Line(f) \
2246 !Is_There_Room_For_A_Char_In_Line(f)
2248 /*---------------------------------------------------------------------------
2249 | Facility : libnform
2250 | Function : static int Insert_String(
2256 | Description : Insert the 'len' characters beginning at pointer 'txt'
2257 | into the 'row' of the 'form'. The insertion occurs
2258 | on the beginning of the row, all other characters are
2259 | moved to the right. After the text a pad character will
2260 | be inserted to separate the text from the rest. If
2261 | necessary the insertion moves characters on the next
2262 | line to make place for the requested insertion string.
2264 | Return Values : E_OK - success
2265 | E_REQUEST_DENIED -
2266 | E_SYSTEM_ERROR - system error
2267 +--------------------------------------------------------------------------*/
2269 Insert_String(FORM *form, int row, FIELD_CELL *txt, int len)
2271 FIELD *field = form->current;
2272 FIELD_CELL *bp = Address_Of_Row_In_Buffer(field, row);
2273 int datalen = (int)(After_End_Of_Data(bp, field->dcols) - bp);
2274 int freelen = field->dcols - datalen;
2275 int requiredlen = len + 1;
2277 int result = E_REQUEST_DENIED;
2279 if (freelen >= requiredlen)
2281 wmove(form->w, row, 0);
2282 myINSNSTR(form->w, txt, len);
2283 wmove(form->w, row, len);
2284 myINSNSTR(form->w, &myBLANK, 1);
2289 /* we have to move characters on the next line. If we are on the
2290 last line this may work, if the field is growable */
2291 if ((row == (field->drows - 1)) && Growable(field))
2293 if (!Field_Grown(field, 1))
2294 return (E_SYSTEM_ERROR);
2295 /* !!!Side-Effect : might be changed due to growth!!! */
2296 bp = Address_Of_Row_In_Buffer(field, row);
2299 if (row < (field->drows - 1))
2302 After_Last_Whitespace_Character(bp,
2303 (int)(Get_Start_Of_Data(bp
2308 /* split points now to the first character of the portion of the
2309 line that must be moved to the next line */
2310 datalen = (int)(split - bp); /* + freelen has to stay on this line */
2311 freelen = field->dcols - (datalen + freelen); /* for the next line */
2313 if ((result = Insert_String(form, row + 1, split, freelen)) == E_OK)
2315 wmove(form->w, row, datalen);
2317 wmove(form->w, row, 0);
2318 myINSNSTR(form->w, txt, len);
2319 wmove(form->w, row, len);
2320 myINSNSTR(form->w, &myBLANK, 1);
2328 /*---------------------------------------------------------------------------
2329 | Facility : libnform
2330 | Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2333 | Description : If a character has been entered into a field, it may
2334 | be that wrapping has to occur. This routine checks
2335 | whether or not wrapping is required and if so, performs
2338 | Return Values : E_OK - no wrapping required or wrapping
2340 | E_REQUEST_DENIED -
2341 | E_SYSTEM_ERROR - some system error
2342 +--------------------------------------------------------------------------*/
2344 Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM *form)
2346 FIELD *field = form->current;
2347 int result = E_REQUEST_DENIED;
2348 bool Last_Row = ((field->drows - 1) == form->currow);
2350 if ((field->opts & O_WRAP) && /* wrapping wanted */
2351 (!Single_Line_Field(field)) && /* must be multi-line */
2352 (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
2353 (!Last_Row || Growable(field))) /* there are more lines */
2357 int chars_to_be_wrapped;
2358 int chars_to_remain_on_line;
2362 /* the above logic already ensures, that in this case the field
2364 if (!Field_Grown(field, 1))
2365 return E_SYSTEM_ERROR;
2367 bp = Address_Of_Current_Row_In_Buffer(form);
2368 Window_To_Buffer(form->w, field);
2369 split = After_Last_Whitespace_Character(bp, field->dcols);
2370 /* split points to the first character of the sequence to be brought
2372 chars_to_remain_on_line = (int)(split - bp);
2373 chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2374 if (chars_to_remain_on_line > 0)
2376 if ((result = Insert_String(form, form->currow + 1, split,
2377 chars_to_be_wrapped)) == E_OK)
2379 wmove(form->w, form->currow, chars_to_remain_on_line);
2381 if (form->curcol >= chars_to_remain_on_line)
2384 form->curcol -= chars_to_remain_on_line;
2394 Window_To_Buffer(form->w, field);
2395 result = E_REQUEST_DENIED;
2399 result = E_OK; /* wrapping was not necessary */
2403 /*----------------------------------------------------------------------------
2404 Field Editing routines
2405 --------------------------------------------------------------------------*/
2407 /*---------------------------------------------------------------------------
2408 | Facility : libnform
2409 | Function : static int Field_Editing(
2410 | int (* const fct) (FORM *),
2413 | Description : Generic routine for field editing requests. The driver
2414 | routines are only called for editable fields, the
2415 | _WINDOW_MODIFIED flag is set if editing occurred.
2416 | This is somewhat special due to the overload semantics
2417 | of the NEW_LINE and DEL_PREV requests.
2419 | Return Values : Error code from low level drivers.
2420 +--------------------------------------------------------------------------*/
2422 Field_Editing(int (*const fct) (FORM *), FORM *form)
2424 int res = E_REQUEST_DENIED;
2426 /* We have to deal here with the specific case of the overloaded
2427 behavior of New_Line and Delete_Previous requests.
2428 They may end up in navigational requests if we are on the first
2429 character in a field. But navigation is also allowed on non-
2432 if ((fct == FE_Delete_Previous) &&
2433 (form->opts & O_BS_OVERLOAD) &&
2434 First_Position_In_Current_Field(form))
2436 res = Inter_Field_Navigation(FN_Previous_Field, form);
2440 if (fct == FE_New_Line)
2442 if ((form->opts & O_NL_OVERLOAD) &&
2443 First_Position_In_Current_Field(form))
2445 res = Inter_Field_Navigation(FN_Next_Field, form);
2448 /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2453 /* From now on, everything must be editable */
2454 if (form->current->opts & O_EDIT)
2458 form->status |= _WINDOW_MODIFIED;
2465 /*---------------------------------------------------------------------------
2466 | Facility : libnform
2467 | Function : static int FE_New_Line(FORM * form)
2469 | Description : Perform a new line request. This is rather complex
2470 | compared to other routines in this code due to the
2471 | rather difficult to understand description in the
2474 | Return Values : E_OK - success
2475 | E_REQUEST_DENIED - new line not allowed
2476 | E_SYSTEM_ERROR - system error
2477 +--------------------------------------------------------------------------*/
2479 FE_New_Line(FORM *form)
2481 FIELD *field = form->current;
2483 bool Last_Row = ((field->drows - 1) == form->currow);
2485 T((T_CALLED("FE_New_Line(%p)"), form));
2486 if (form->status & _OVLMODE)
2489 (!(Growable(field) && !Single_Line_Field(field))))
2491 if (!(form->opts & O_NL_OVERLOAD))
2492 returnCode(E_REQUEST_DENIED);
2493 wmove(form->w, form->currow, form->curcol);
2495 /* we have to set this here, although it is also
2496 handled in the generic routine. The reason is,
2497 that FN_Next_Field may fail, but the form is
2498 definitively changed */
2499 form->status |= _WINDOW_MODIFIED;
2500 returnCode(Inter_Field_Navigation(FN_Next_Field, form));
2504 if (Last_Row && !Field_Grown(field, 1))
2506 /* N.B.: due to the logic in the 'if', LastRow==TRUE
2507 means here that the field is growable and not
2508 a single-line field */
2509 returnCode(E_SYSTEM_ERROR);
2511 wmove(form->w, form->currow, form->curcol);
2515 form->status |= _WINDOW_MODIFIED;
2523 !(Growable(field) && !Single_Line_Field(field)))
2525 if (!(form->opts & O_NL_OVERLOAD))
2526 returnCode(E_REQUEST_DENIED);
2527 returnCode(Inter_Field_Navigation(FN_Next_Field, form));
2531 bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2533 if (!(May_Do_It || Growable(field)))
2534 returnCode(E_REQUEST_DENIED);
2535 if (!May_Do_It && !Field_Grown(field, 1))
2536 returnCode(E_SYSTEM_ERROR);
2538 bp = Address_Of_Current_Position_In_Buffer(form);
2539 t = After_End_Of_Data(bp, field->dcols - form->curcol);
2540 wmove(form->w, form->currow, form->curcol);
2544 wmove(form->w, form->currow, form->curcol);
2546 myADDNSTR(form->w, bp, (int)(t - bp));
2547 form->status |= _WINDOW_MODIFIED;
2553 /*---------------------------------------------------------------------------
2554 | Facility : libnform
2555 | Function : static int FE_Insert_Character(FORM * form)
2557 | Description : Insert blank character at the cursor position
2559 | Return Values : E_OK
2561 +--------------------------------------------------------------------------*/
2563 FE_Insert_Character(FORM *form)
2565 FIELD *field = form->current;
2566 int result = E_REQUEST_DENIED;
2568 T((T_CALLED("FE_Insert_Character(%p)"), form));
2569 if (Check_Char(field->type, (int)C_BLANK, (TypeArgument *)(field->arg)))
2571 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2573 if (There_Is_Room ||
2574 ((Single_Line_Field(field) && Growable(field))))
2576 if (!There_Is_Room && !Field_Grown(field, 1))
2577 result = E_SYSTEM_ERROR;
2580 winsch(form->w, (chtype)C_BLANK);
2581 result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2588 /*---------------------------------------------------------------------------
2589 | Facility : libnform
2590 | Function : static int FE_Insert_Line(FORM * form)
2592 | Description : Insert a blank line at the cursor position
2594 | Return Values : E_OK - success
2595 | E_REQUEST_DENIED - line can not be inserted
2596 +--------------------------------------------------------------------------*/
2598 FE_Insert_Line(FORM *form)
2600 FIELD *field = form->current;
2601 int result = E_REQUEST_DENIED;
2603 T((T_CALLED("FE_Insert_Line(%p)"), form));
2604 if (Check_Char(field->type, (int)C_BLANK, (TypeArgument *)(field->arg)))
2606 bool Maybe_Done = (form->currow != (field->drows - 1)) &&
2607 Is_There_Room_For_A_Line(form);
2609 if (!Single_Line_Field(field) &&
2610 (Maybe_Done || Growable(field)))
2612 if (!Maybe_Done && !Field_Grown(field, 1))
2613 result = E_SYSTEM_ERROR;
2625 /*---------------------------------------------------------------------------
2626 | Facility : libnform
2627 | Function : static int FE_Delete_Character(FORM * form)
2629 | Description : Delete character at the cursor position
2631 | Return Values : E_OK - success
2632 +--------------------------------------------------------------------------*/
2634 FE_Delete_Character(FORM *form)
2636 T((T_CALLED("FE_Delete_Character(%p)"), form));
2641 /*---------------------------------------------------------------------------
2642 | Facility : libnform
2643 | Function : static int FE_Delete_Previous(FORM * form)
2645 | Description : Delete character before cursor. Again this is a rather
2646 | difficult piece compared to others due to the overloading
2647 | semantics of backspace.
2648 | N.B.: The case of overloaded BS on first field position
2649 | is already handled in the generic routine.
2651 | Return Values : E_OK - success
2652 | E_REQUEST_DENIED - Character can't be deleted
2653 +--------------------------------------------------------------------------*/
2655 FE_Delete_Previous(FORM *form)
2657 FIELD *field = form->current;
2659 T((T_CALLED("FE_Delete_Previous(%p)"), form));
2660 if (First_Position_In_Current_Field(form))
2661 returnCode(E_REQUEST_DENIED);
2663 if ((--(form->curcol)) < 0)
2665 FIELD_CELL *this_line, *prev_line, *prev_end, *this_end;
2666 int this_row = form->currow;
2669 if (form->status & _OVLMODE)
2670 returnCode(E_REQUEST_DENIED);
2672 prev_line = Address_Of_Row_In_Buffer(field, (form->currow - 1));
2673 this_line = Address_Of_Row_In_Buffer(field, (form->currow));
2674 Synchronize_Buffer(form);
2675 prev_end = After_End_Of_Data(prev_line, field->dcols);
2676 this_end = After_End_Of_Data(this_line, field->dcols);
2677 if ((int)(this_end - this_line) >
2678 (field->cols - (int)(prev_end - prev_line)))
2679 returnCode(E_REQUEST_DENIED);
2680 wmove(form->w, form->currow, form->curcol);
2682 Adjust_Cursor_Position(form, prev_end);
2684 * If we did not really move to the previous line, help the user a
2685 * little. It is however a little inconsistent. Normally, when
2686 * backspacing around the point where text wraps to a new line in a
2687 * multi-line form, we absorb one keystroke for the wrapping point. That
2688 * is consistent with SVr4 forms. However, SVr4 does not allow typing
2689 * into the last column of the field, and requires the user to enter a
2690 * newline to move to the next line. Therefore it can consistently eat
2691 * that keystroke. Since ncurses allows the last column, it wraps
2692 * automatically (given the proper options). But we cannot eat the
2693 * keystroke to back over the wrapping point, since that would put the
2694 * cursor past the end of the form field. In this case, just delete the
2695 * character at the end of the field.
2697 if (form->currow == this_row && this_row > 0)
2700 form->curcol = field->dcols - 1;
2705 wmove(form->w, form->currow, form->curcol);
2706 myADDNSTR(form->w, this_line, (int)(this_end - this_line));
2716 /*---------------------------------------------------------------------------
2717 | Facility : libnform
2718 | Function : static int FE_Delete_Line(FORM * form)
2720 | Description : Delete line at cursor position.
2722 | Return Values : E_OK - success
2723 +--------------------------------------------------------------------------*/
2725 FE_Delete_Line(FORM *form)
2727 T((T_CALLED("FE_Delete_Line(%p)"), form));
2733 /*---------------------------------------------------------------------------
2734 | Facility : libnform
2735 | Function : static int FE_Delete_Word(FORM * form)
2737 | Description : Delete word at cursor position
2739 | Return Values : E_OK - success
2740 | E_REQUEST_DENIED - failure
2741 +--------------------------------------------------------------------------*/
2743 FE_Delete_Word(FORM *form)
2745 FIELD *field = form->current;
2746 FIELD_CELL *bp = Address_Of_Current_Row_In_Buffer(form);
2747 FIELD_CELL *ep = bp + field->dcols;
2748 FIELD_CELL *cp = bp + form->curcol;
2751 T((T_CALLED("FE_Delete_Word(%p)"), form));
2752 Synchronize_Buffer(form);
2754 returnCode(E_REQUEST_DENIED); /* not in word */
2756 /* move cursor to begin of word and erase to end of screen-line */
2757 Adjust_Cursor_Position(form,
2758 After_Last_Whitespace_Character(bp, form->curcol));
2759 wmove(form->w, form->currow, form->curcol);
2762 /* skip over word in buffer */
2763 s = Get_First_Whitespace_Character(cp, (int)(ep - cp));
2764 /* to begin of next word */
2765 s = Get_Start_Of_Data(s, (int)(ep - s));
2766 if ((s != cp) && !ISBLANK(*s))
2768 /* copy remaining line to window */
2769 myADDNSTR(form->w, s, (int)(s - After_End_Of_Data(s, (int)(ep - s))));
2774 /*---------------------------------------------------------------------------
2775 | Facility : libnform
2776 | Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2778 | Description : Clear to end of current line.
2780 | Return Values : E_OK - success
2781 +--------------------------------------------------------------------------*/
2783 FE_Clear_To_End_Of_Line(FORM *form)
2785 T((T_CALLED("FE_Clear_To_End_Of_Line(%p)"), form));
2786 wmove(form->w, form->currow, form->curcol);
2791 /*---------------------------------------------------------------------------
2792 | Facility : libnform
2793 | Function : static int FE_Clear_To_End_Of_Field(FORM * form)
2795 | Description : Clear to end of field.
2797 | Return Values : E_OK - success
2798 +--------------------------------------------------------------------------*/
2800 FE_Clear_To_End_Of_Field(FORM *form)
2802 T((T_CALLED("FE_Clear_To_End_Of_Field(%p)"), form));
2803 wmove(form->w, form->currow, form->curcol);
2808 /*---------------------------------------------------------------------------
2809 | Facility : libnform
2810 | Function : static int FE_Clear_Field(FORM * form)
2812 | Description : Clear entire field.
2814 | Return Values : E_OK - success
2815 +--------------------------------------------------------------------------*/
2817 FE_Clear_Field(FORM *form)
2819 T((T_CALLED("FE_Clear_Field(%p)"), form));
2820 form->currow = form->curcol = 0;
2824 /*----------------------------------------------------------------------------
2825 END of Field Editing routines
2826 --------------------------------------------------------------------------*/
2828 /*----------------------------------------------------------------------------
2830 --------------------------------------------------------------------------*/
2832 /*---------------------------------------------------------------------------
2833 | Facility : libnform
2834 | Function : static int EM_Overlay_Mode(FORM * form)
2836 | Description : Switch to overlay mode.
2838 | Return Values : E_OK - success
2839 +--------------------------------------------------------------------------*/
2841 EM_Overlay_Mode(FORM *form)
2843 T((T_CALLED("EM_Overlay_Mode(%p)"), form));
2844 form->status |= _OVLMODE;
2848 /*---------------------------------------------------------------------------
2849 | Facility : libnform
2850 | Function : static int EM_Insert_Mode(FORM * form)
2852 | Description : Switch to insert mode
2854 | Return Values : E_OK - success
2855 +--------------------------------------------------------------------------*/
2857 EM_Insert_Mode(FORM *form)
2859 T((T_CALLED("EM_Insert_Mode(%p)"), form));
2860 form->status &= ~_OVLMODE;
2864 /*----------------------------------------------------------------------------
2865 END of Edit Mode routines
2866 --------------------------------------------------------------------------*/
2868 /*----------------------------------------------------------------------------
2869 Helper routines for Choice Requests
2870 --------------------------------------------------------------------------*/
2872 /*---------------------------------------------------------------------------
2873 | Facility : libnform
2874 | Function : static bool Next_Choice(
2877 | TypeArgument *argp)
2879 | Description : Get the next field choice. For linked types this is
2882 | Return Values : TRUE - next choice successfully retrieved
2883 | FALSE - couldn't retrieve next choice
2884 +--------------------------------------------------------------------------*/
2886 Next_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2888 if (!typ || !(typ->status & _HAS_CHOICE))
2891 if (typ->status & _LINKED_TYPE)
2895 Next_Choice(typ->left, field, argp->left) ||
2896 Next_Choice(typ->right, field, argp->right));
2901 return typ->next(field, (void *)argp);
2905 /*---------------------------------------------------------------------------
2906 | Facility : libnform
2907 | Function : static bool Previous_Choice(
2910 | TypeArgument *argp)
2912 | Description : Get the previous field choice. For linked types this
2913 | is done recursively.
2915 | Return Values : TRUE - previous choice successfully retrieved
2916 | FALSE - couldn't retrieve previous choice
2917 +--------------------------------------------------------------------------*/
2919 Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2921 if (!typ || !(typ->status & _HAS_CHOICE))
2924 if (typ->status & _LINKED_TYPE)
2928 Previous_Choice(typ->left, field, argp->left) ||
2929 Previous_Choice(typ->right, field, argp->right));
2934 return typ->prev(field, (void *)argp);
2937 /*----------------------------------------------------------------------------
2938 End of Helper routines for Choice Requests
2939 --------------------------------------------------------------------------*/
2941 /*----------------------------------------------------------------------------
2942 Routines for Choice Requests
2943 --------------------------------------------------------------------------*/
2945 /*---------------------------------------------------------------------------
2946 | Facility : libnform
2947 | Function : static int CR_Next_Choice(FORM * form)
2949 | Description : Get the next field choice.
2951 | Return Values : E_OK - success
2952 | E_REQUEST_DENIED - next choice couldn't be retrieved
2953 +--------------------------------------------------------------------------*/
2955 CR_Next_Choice(FORM *form)
2957 FIELD *field = form->current;
2959 T((T_CALLED("CR_Next_Choice(%p)"), form));
2960 Synchronize_Buffer(form);
2961 returnCode((Next_Choice(field->type, field, (TypeArgument *)(field->arg)))
2963 : E_REQUEST_DENIED);
2966 /*---------------------------------------------------------------------------
2967 | Facility : libnform
2968 | Function : static int CR_Previous_Choice(FORM * form)
2970 | Description : Get the previous field choice.
2972 | Return Values : E_OK - success
2973 | E_REQUEST_DENIED - prev. choice couldn't be retrieved
2974 +--------------------------------------------------------------------------*/
2976 CR_Previous_Choice(FORM *form)
2978 FIELD *field = form->current;
2980 T((T_CALLED("CR_Previous_Choice(%p)"), form));
2981 Synchronize_Buffer(form);
2982 returnCode((Previous_Choice(field->type, field, (TypeArgument *)(field->arg)))
2984 : E_REQUEST_DENIED);
2986 /*----------------------------------------------------------------------------
2987 End of Routines for Choice Requests
2988 --------------------------------------------------------------------------*/
2990 /*----------------------------------------------------------------------------
2991 Helper routines for Field Validations.
2992 --------------------------------------------------------------------------*/
2994 /*---------------------------------------------------------------------------
2995 | Facility : libnform
2996 | Function : static bool Check_Field(
2999 | TypeArgument * argp)
3001 | Description : Check the field according to its fieldtype and its
3002 | actual arguments. For linked fieldtypes this is done
3005 | Return Values : TRUE - field is valid
3006 | FALSE - field is invalid.
3007 +--------------------------------------------------------------------------*/
3009 Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
3013 if (field->opts & O_NULLOK)
3015 FIELD_CELL *bp = field->buf;
3018 while (ISBLANK(*bp))
3022 if (CharOf(*bp) == 0)
3026 if (typ->status & _LINKED_TYPE)
3030 Check_Field(typ->left, field, argp->left) ||
3031 Check_Field(typ->right, field, argp->right));
3036 return typ->fcheck(field, (void *)argp);
3042 /*---------------------------------------------------------------------------
3043 | Facility : libnform
3044 | Function : bool _nc_Internal_Validation(FORM * form )
3046 | Description : Validate the current field of the form.
3048 | Return Values : TRUE - field is valid
3049 | FALSE - field is invalid
3050 +--------------------------------------------------------------------------*/
3051 NCURSES_EXPORT(bool)
3052 _nc_Internal_Validation(FORM *form)
3056 field = form->current;
3058 Synchronize_Buffer(form);
3059 if ((form->status & _FCHECK_REQUIRED) ||
3060 (!(field->opts & O_PASSOK)))
3062 if (!Check_Field(field->type, field, (TypeArgument *)(field->arg)))
3064 form->status &= ~_FCHECK_REQUIRED;
3065 field->status |= _CHANGED;
3066 Synchronize_Linked_Fields(field);
3070 /*----------------------------------------------------------------------------
3071 End of Helper routines for Field Validations.
3072 --------------------------------------------------------------------------*/
3074 /*----------------------------------------------------------------------------
3075 Routines for Field Validation.
3076 --------------------------------------------------------------------------*/
3078 /*---------------------------------------------------------------------------
3079 | Facility : libnform
3080 | Function : static int FV_Validation(FORM * form)
3082 | Description : Validate the current field of the form.
3084 | Return Values : E_OK - field valid
3085 | E_INVALID_FIELD - field not valid
3086 +--------------------------------------------------------------------------*/
3088 FV_Validation(FORM *form)
3090 T((T_CALLED("FV_Validation(%p)"), form));
3091 if (_nc_Internal_Validation(form))
3094 returnCode(E_INVALID_FIELD);
3096 /*----------------------------------------------------------------------------
3097 End of routines for Field Validation.
3098 --------------------------------------------------------------------------*/
3100 /*----------------------------------------------------------------------------
3101 Helper routines for Inter-Field Navigation
3102 --------------------------------------------------------------------------*/
3104 /*---------------------------------------------------------------------------
3105 | Facility : libnform
3106 | Function : static FIELD *Next_Field_On_Page(FIELD * field)
3108 | Description : Get the next field after the given field on the current
3109 | page. The order of fields is the one defined by the
3110 | fields array. Only visible and active fields are
3113 | Return Values : Pointer to the next field.
3114 +--------------------------------------------------------------------------*/
3115 NCURSES_INLINE static FIELD *
3116 Next_Field_On_Page(FIELD *field)
3118 FORM *form = field->form;
3119 FIELD **field_on_page = &form->field[field->index];
3120 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
3121 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
3126 (field_on_page == last_on_page) ? first_on_page : field_on_page + 1;
3127 if (Field_Is_Selectable(*field_on_page))
3130 while (field != (*field_on_page));
3131 return (*field_on_page);
3134 /*---------------------------------------------------------------------------
3135 | Facility : libnform
3136 | Function : FIELD* _nc_First_Active_Field(FORM * form)
3138 | Description : Get the first active field on the current page,
3139 | if there are such. If there are none, get the first
3140 | visible field on the page. If there are also none,
3141 | we return the first field on page and hope the best.
3143 | Return Values : Pointer to calculated field.
3144 +--------------------------------------------------------------------------*/
3145 NCURSES_EXPORT(FIELD *)
3146 _nc_First_Active_Field(FORM *form)
3148 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
3149 FIELD *proposed = Next_Field_On_Page(*last_on_page);
3151 if (proposed == *last_on_page)
3153 /* there might be the special situation, where there is no
3154 active and visible field on the current page. We then select
3155 the first visible field on this readonly page
3157 if (Field_Is_Not_Selectable(proposed))
3159 FIELD **field = &form->field[proposed->index];
3160 FIELD **first = &form->field[form->page[form->curpage].pmin];
3164 field = (field == last_on_page) ? first : field + 1;
3165 if (((*field)->opts & O_VISIBLE))
3168 while (proposed != (*field));
3172 if ((proposed == *last_on_page) && !(proposed->opts & O_VISIBLE))
3174 /* This means, there is also no visible field on the page.
3175 So we propose the first one and hope the very best...
3176 Some very clever user has designed a readonly and invisible
3186 /*---------------------------------------------------------------------------
3187 | Facility : libnform
3188 | Function : static FIELD *Previous_Field_On_Page(FIELD * field)
3190 | Description : Get the previous field before the given field on the
3191 | current page. The order of fields is the one defined by
3192 | the fields array. Only visible and active fields are
3195 | Return Values : Pointer to the previous field.
3196 +--------------------------------------------------------------------------*/
3197 NCURSES_INLINE static FIELD *
3198 Previous_Field_On_Page(FIELD *field)
3200 FORM *form = field->form;
3201 FIELD **field_on_page = &form->field[field->index];
3202 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
3203 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
3208 (field_on_page == first_on_page) ? last_on_page : field_on_page - 1;
3209 if (Field_Is_Selectable(*field_on_page))
3212 while (field != (*field_on_page));
3214 return (*field_on_page);
3217 /*---------------------------------------------------------------------------
3218 | Facility : libnform
3219 | Function : static FIELD *Sorted_Next_Field(FIELD * field)
3221 | Description : Get the next field after the given field on the current
3222 | page. The order of fields is the one defined by the
3223 | (row,column) geometry, rows are major.
3225 | Return Values : Pointer to the next field.
3226 +--------------------------------------------------------------------------*/
3227 NCURSES_INLINE static FIELD *
3228 Sorted_Next_Field(FIELD *field)
3230 FIELD *field_on_page = field;
3234 field_on_page = field_on_page->snext;
3235 if (Field_Is_Selectable(field_on_page))
3238 while (field_on_page != field);
3240 return (field_on_page);
3243 /*---------------------------------------------------------------------------
3244 | Facility : libnform
3245 | Function : static FIELD *Sorted_Previous_Field(FIELD * field)
3247 | Description : Get the previous field before the given field on the
3248 | current page. The order of fields is the one defined
3249 | by the (row,column) geometry, rows are major.
3251 | Return Values : Pointer to the previous field.
3252 +--------------------------------------------------------------------------*/
3253 NCURSES_INLINE static FIELD *
3254 Sorted_Previous_Field(FIELD *field)
3256 FIELD *field_on_page = field;
3260 field_on_page = field_on_page->sprev;
3261 if (Field_Is_Selectable(field_on_page))
3264 while (field_on_page != field);
3266 return (field_on_page);
3269 /*---------------------------------------------------------------------------
3270 | Facility : libnform
3271 | Function : static FIELD *Left_Neighbor_Field(FIELD * field)
3273 | Description : Get the left neighbor of the field on the same line
3274 | and the same page. Cycles through the line.
3276 | Return Values : Pointer to left neighbor field.
3277 +--------------------------------------------------------------------------*/
3278 NCURSES_INLINE static FIELD *
3279 Left_Neighbor_Field(FIELD *field)
3281 FIELD *field_on_page = field;
3283 /* For a field that has really a left neighbor, the while clause
3284 immediately fails and the loop is left, positioned at the right
3285 neighbor. Otherwise we cycle backwards through the sorted field list
3286 until we enter the same line (from the right end).
3290 field_on_page = Sorted_Previous_Field(field_on_page);
3292 while (field_on_page->frow != field->frow);
3294 return (field_on_page);
3297 /*---------------------------------------------------------------------------
3298 | Facility : libnform
3299 | Function : static FIELD *Right_Neighbor_Field(FIELD * field)
3301 | Description : Get the right neighbor of the field on the same line
3302 | and the same page.
3304 | Return Values : Pointer to right neighbor field.
3305 +--------------------------------------------------------------------------*/
3306 NCURSES_INLINE static FIELD *
3307 Right_Neighbor_Field(FIELD *field)
3309 FIELD *field_on_page = field;
3311 /* See the comments on Left_Neighbor_Field to understand how it works */
3314 field_on_page = Sorted_Next_Field(field_on_page);
3316 while (field_on_page->frow != field->frow);
3318 return (field_on_page);
3321 /*---------------------------------------------------------------------------
3322 | Facility : libnform
3323 | Function : static FIELD *Upper_Neighbor_Field(FIELD * field)
3325 | Description : Because of the row-major nature of sorting the fields,
3326 | it is more difficult to define whats the upper neighbor
3327 | field really means. We define that it must be on a
3328 | 'previous' line (cyclic order!) and is the rightmost
3329 | field laying on the left side of the given field. If
3330 | this set is empty, we take the first field on the line.
3332 | Return Values : Pointer to the upper neighbor field.
3333 +--------------------------------------------------------------------------*/
3335 Upper_Neighbor_Field(FIELD *field)
3337 FIELD *field_on_page = field;
3338 int frow = field->frow;
3339 int fcol = field->fcol;
3341 /* Walk back to the 'previous' line. The second term in the while clause
3342 just guarantees that we stop if we cycled through the line because
3343 there might be no 'previous' line if the page has just one line.
3347 field_on_page = Sorted_Previous_Field(field_on_page);
3349 while (field_on_page->frow == frow && field_on_page->fcol != fcol);
3351 if (field_on_page->frow != frow)
3353 /* We really found a 'previous' line. We are positioned at the
3354 rightmost field on this line */
3355 frow = field_on_page->frow;
3357 /* We walk to the left as long as we are really right of the
3359 while (field_on_page->frow == frow && field_on_page->fcol > fcol)
3360 field_on_page = Sorted_Previous_Field(field_on_page);
3362 /* If we wrapped, just go to the right which is the first field on
3364 if (field_on_page->frow != frow)
3365 field_on_page = Sorted_Next_Field(field_on_page);
3368 return (field_on_page);
3371 /*---------------------------------------------------------------------------
3372 | Facility : libnform
3373 | Function : static FIELD *Down_Neighbor_Field(FIELD * field)
3375 | Description : Because of the row-major nature of sorting the fields,
3376 | its more difficult to define whats the down neighbor
3377 | field really means. We define that it must be on a
3378 | 'next' line (cyclic order!) and is the leftmost
3379 | field laying on the right side of the given field. If
3380 | this set is empty, we take the last field on the line.
3382 | Return Values : Pointer to the upper neighbor field.
3383 +--------------------------------------------------------------------------*/
3385 Down_Neighbor_Field(FIELD *field)
3387 FIELD *field_on_page = field;
3388 int frow = field->frow;
3389 int fcol = field->fcol;
3391 /* Walk forward to the 'next' line. The second term in the while clause
3392 just guarantees that we stop if we cycled through the line because
3393 there might be no 'next' line if the page has just one line.
3397 field_on_page = Sorted_Next_Field(field_on_page);
3399 while (field_on_page->frow == frow && field_on_page->fcol != fcol);
3401 if (field_on_page->frow != frow)
3403 /* We really found a 'next' line. We are positioned at the rightmost
3404 field on this line */
3405 frow = field_on_page->frow;
3407 /* We walk to the right as long as we are really left of the
3409 while (field_on_page->frow == frow && field_on_page->fcol < fcol)
3410 field_on_page = Sorted_Next_Field(field_on_page);
3412 /* If we wrapped, just go to the left which is the last field on
3414 if (field_on_page->frow != frow)
3415 field_on_page = Sorted_Previous_Field(field_on_page);
3418 return (field_on_page);
3421 /*----------------------------------------------------------------------------
3422 Inter-Field Navigation routines
3423 --------------------------------------------------------------------------*/
3425 /*---------------------------------------------------------------------------
3426 | Facility : libnform
3427 | Function : static int Inter_Field_Navigation(
3428 | int (* const fct) (FORM *),
3431 | Description : Generic behavior for changing the current field, the
3432 | field is left and a new field is entered. So the field
3433 | must be validated and the field init/term hooks must
3436 | Return Values : E_OK - success
3437 | E_INVALID_FIELD - field is invalid
3438 | some other - error from subordinate call
3439 +--------------------------------------------------------------------------*/
3441 Inter_Field_Navigation(int (*const fct) (FORM *), FORM *form)
3445 if (!_nc_Internal_Validation(form))
3446 res = E_INVALID_FIELD;
3449 Call_Hook(form, fieldterm);
3451 Call_Hook(form, fieldinit);
3456 /*---------------------------------------------------------------------------
3457 | Facility : libnform
3458 | Function : static int FN_Next_Field(FORM * form)
3460 | Description : Move to the next field on the current page of the form
3462 | Return Values : E_OK - success
3463 | != E_OK - error from subordinate call
3464 +--------------------------------------------------------------------------*/
3466 FN_Next_Field(FORM *form)
3468 T((T_CALLED("FN_Next_Field(%p)"), form));
3469 returnCode(_nc_Set_Current_Field(form,
3470 Next_Field_On_Page(form->current)));
3473 /*---------------------------------------------------------------------------
3474 | Facility : libnform
3475 | Function : static int FN_Previous_Field(FORM * form)
3477 | Description : Move to the previous field on the current page of the
3480 | Return Values : E_OK - success
3481 | != E_OK - error from subordinate call
3482 +--------------------------------------------------------------------------*/
3484 FN_Previous_Field(FORM *form)
3486 T((T_CALLED("FN_Previous_Field(%p)"), form));
3487 returnCode(_nc_Set_Current_Field(form,
3488 Previous_Field_On_Page(form->current)));
3491 /*---------------------------------------------------------------------------
3492 | Facility : libnform
3493 | Function : static int FN_First_Field(FORM * form)
3495 | Description : Move to the first field on the current page of the form
3497 | Return Values : E_OK - success
3498 | != E_OK - error from subordinate call
3499 +--------------------------------------------------------------------------*/
3501 FN_First_Field(FORM *form)
3503 T((T_CALLED("FN_First_Field(%p)"), form));
3504 returnCode(_nc_Set_Current_Field(form,
3505 Next_Field_On_Page(form->field[form->page[form->curpage].pmax])));
3508 /*---------------------------------------------------------------------------
3509 | Facility : libnform
3510 | Function : static int FN_Last_Field(FORM * form)
3512 | Description : Move to the last field on the current page of the form
3514 | Return Values : E_OK - success
3515 | != E_OK - error from subordinate call
3516 +--------------------------------------------------------------------------*/
3518 FN_Last_Field(FORM *form)
3520 T((T_CALLED("FN_Last_Field(%p)"), form));
3522 _nc_Set_Current_Field(form,
3523 Previous_Field_On_Page(form->field[form->page[form->curpage].pmin])));
3526 /*---------------------------------------------------------------------------
3527 | Facility : libnform
3528 | Function : static int FN_Sorted_Next_Field(FORM * form)
3530 | Description : Move to the sorted next field on the current page
3533 | Return Values : E_OK - success
3534 | != E_OK - error from subordinate call
3535 +--------------------------------------------------------------------------*/
3537 FN_Sorted_Next_Field(FORM *form)
3539 T((T_CALLED("FN_Sorted_Next_Field(%p)"), form));
3540 returnCode(_nc_Set_Current_Field(form,
3541 Sorted_Next_Field(form->current)));
3544 /*---------------------------------------------------------------------------
3545 | Facility : libnform
3546 | Function : static int FN_Sorted_Previous_Field(FORM * form)
3548 | Description : Move to the sorted previous field on the current page
3551 | Return Values : E_OK - success
3552 | != E_OK - error from subordinate call
3553 +--------------------------------------------------------------------------*/
3555 FN_Sorted_Previous_Field(FORM *form)
3557 T((T_CALLED("FN_Sorted_Previous_Field(%p)"), form));
3558 returnCode(_nc_Set_Current_Field(form,
3559 Sorted_Previous_Field(form->current)));
3562 /*---------------------------------------------------------------------------
3563 | Facility : libnform
3564 | Function : static int FN_Sorted_First_Field(FORM * form)
3566 | Description : Move to the sorted first field on the current page
3569 | Return Values : E_OK - success
3570 | != E_OK - error from subordinate call
3571 +--------------------------------------------------------------------------*/
3573 FN_Sorted_First_Field(FORM *form)
3575 T((T_CALLED("FN_Sorted_First_Field(%p)"), form));
3576 returnCode(_nc_Set_Current_Field(form,
3577 Sorted_Next_Field(form->field[form->page[form->curpage].smax])));
3580 /*---------------------------------------------------------------------------
3581 | Facility : libnform
3582 | Function : static int FN_Sorted_Last_Field(FORM * form)
3584 | Description : Move to the sorted last field on the current page
3587 | Return Values : E_OK - success
3588 | != E_OK - error from subordinate call
3589 +--------------------------------------------------------------------------*/
3591 FN_Sorted_Last_Field(FORM *form)
3593 T((T_CALLED("FN_Sorted_Last_Field(%p)"), form));
3594 returnCode(_nc_Set_Current_Field(form,
3595 Sorted_Previous_Field(form->field[form->page[form->curpage].smin])));
3598 /*---------------------------------------------------------------------------
3599 | Facility : libnform
3600 | Function : static int FN_Left_Field(FORM * form)
3602 | Description : Get the field on the left of the current field on the
3603 | same line and the same page. Cycles through the line.
3605 | Return Values : E_OK - success
3606 | != E_OK - error from subordinate call
3607 +--------------------------------------------------------------------------*/
3609 FN_Left_Field(FORM *form)
3611 T((T_CALLED("FN_Left_Field(%p)"), form));
3612 returnCode(_nc_Set_Current_Field(form,
3613 Left_Neighbor_Field(form->current)));
3616 /*---------------------------------------------------------------------------
3617 | Facility : libnform
3618 | Function : static int FN_Right_Field(FORM * form)
3620 | Description : Get the field on the right of the current field on the
3621 | same line and the same page. Cycles through the line.
3623 | Return Values : E_OK - success
3624 | != E_OK - error from subordinate call
3625 +--------------------------------------------------------------------------*/
3627 FN_Right_Field(FORM *form)
3629 T((T_CALLED("FN_Right_Field(%p)"), form));
3630 returnCode(_nc_Set_Current_Field(form,
3631 Right_Neighbor_Field(form->current)));
3634 /*---------------------------------------------------------------------------
3635 | Facility : libnform
3636 | Function : static int FN_Up_Field(FORM * form)
3638 | Description : Get the upper neighbor of the current field. This
3639 | cycles through the page. See the comments of the
3640 | Upper_Neighbor_Field function to understand how
3641 | 'upper' is defined.
3643 | Return Values : E_OK - success
3644 | != E_OK - error from subordinate call
3645 +--------------------------------------------------------------------------*/
3647 FN_Up_Field(FORM *form)
3649 T((T_CALLED("FN_Up_Field(%p)"), form));
3650 returnCode(_nc_Set_Current_Field(form,
3651 Upper_Neighbor_Field(form->current)));
3654 /*---------------------------------------------------------------------------
3655 | Facility : libnform
3656 | Function : static int FN_Down_Field(FORM * form)
3658 | Description : Get the down neighbor of the current field. This
3659 | cycles through the page. See the comments of the
3660 | Down_Neighbor_Field function to understand how
3661 | 'down' is defined.
3663 | Return Values : E_OK - success
3664 | != E_OK - error from subordinate call
3665 +--------------------------------------------------------------------------*/
3667 FN_Down_Field(FORM *form)
3669 T((T_CALLED("FN_Down_Field(%p)"), form));
3670 returnCode(_nc_Set_Current_Field(form,
3671 Down_Neighbor_Field(form->current)));
3673 /*----------------------------------------------------------------------------
3674 END of Field Navigation routines
3675 --------------------------------------------------------------------------*/
3677 /*----------------------------------------------------------------------------
3678 Helper routines for Page Navigation
3679 --------------------------------------------------------------------------*/
3681 /*---------------------------------------------------------------------------
3682 | Facility : libnform
3683 | Function : int _nc_Set_Form_Page(FORM * form,
3687 | Description : Make the given page number the current page and make
3688 | the given field the current field on the page. If
3689 | for the field NULL is given, make the first field on
3690 | the page the current field. The routine acts only
3691 | if the requested page is not the current page.
3693 | Return Values : E_OK - success
3694 | != E_OK - error from subordinate call
3695 | E_BAD_ARGUMENT - invalid field pointer
3696 | E_SYSTEM_ERROR - some severe basic error
3697 +--------------------------------------------------------------------------*/
3699 _nc_Set_Form_Page(FORM *form, int page, FIELD *field)