1 /****************************************************************************
2 * Copyright (c) 1998 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 <juergen.pfeifer@gmx.net> 1995,1997 *
31 ****************************************************************************/
32 #include "form.priv.h"
34 MODULE_ID("$Id: frm_driver.c,v 1.35 1999/05/16 17:20:52 juergen Exp $")
36 /*----------------------------------------------------------------------------
37 This is the core module of the form library. It contains the majority
38 of the driver routines as well as the form_driver function.
40 Essentially this module is nearly the whole library. This is because
41 all the functions in this module depends on some others in the module,
42 so it makes no sense to split them into separate files because they
43 will always be linked together. The only acceptable concern is turnaround
44 time for this module, but now we have all Pentiums or Riscs, so what!
46 The driver routines are grouped into nine generic categories:
48 a) Page Navigation ( all functions prefixed by PN_ )
49 The current page of the form is left and some new page is
51 b) Inter-Field Navigation ( all functions prefixed by FN_ )
52 The current field of the form is left and some new field is
54 c) Intra-Field Navigation ( all functions prefixed by IFN_ )
55 The current position in the current field is changed.
56 d) Vertical Scrolling ( all functions prefixed by VSC_ )
57 Esseantially this is a specialization of Intra-Field navigation.
58 It has to check for a multi-line field.
59 e) Horizontal Scrolling ( all functions prefixed by HSC_ )
60 Esseantially this is a specialization of Intra-Field navigation.
61 It has to check for a single-line field.
62 f) Field Editing ( all functions prefixed by FE_ )
63 The content of the current field is changed
64 g) Edit Mode requests ( all functions prefixed by EM_ )
65 Switching between insert and overlay mode
66 h) Field-Validation requests ( all functions prefixed by FV_ )
67 Perform verifications of the field.
68 i) Choice requests ( all functions prefixed by CR_ )
69 Requests to enumerate possible field values
70 --------------------------------------------------------------------------*/
72 /*----------------------------------------------------------------------------
73 Some remarks on the placements of assert() macros :
74 I use them only on "strategic" places, i.e. top level entries where
75 I want to make sure that things are set correctly. Throughout subordinate
76 routines I omit them mostly.
77 --------------------------------------------------------------------------*/
80 Some options that may effect compatibility in behavior to SVr4 forms,
81 but they are here to allow a more intuitive and user friendly behaviour of
82 our form implementation. This doesn't affect the API, so we feel it is
85 The initial implementation tries to stay very close with the behaviour
86 of the original SVr4 implementation, although in some areas it is quite
87 clear that this isn't the most appropriate way. As far as possible this
88 sources will allow you to build a forms lib that behaves quite similar
89 to SVr4, but now and in the future we will give you better options.
90 Perhaps at some time we will make this configurable at runtime.
93 /* Implement a more user-friendly previous/next word behaviour */
94 #define FRIENDLY_PREV_NEXT_WORD (1)
95 /* Fix the wrong behaviour for forms with all fields inactive */
96 #define FIX_FORM_INACTIVE_BUG (1)
97 /* Allow dynamic field growth also when navigating past the end */
98 #define GROW_IF_NAVIGATE (1)
100 /*----------------------------------------------------------------------------
101 Forward references to some internally used static functions
102 --------------------------------------------------------------------------*/
103 static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
104 static int FN_Next_Field (FORM * form);
105 static int FN_Previous_Field (FORM * form);
106 static int FE_New_Line(FORM *);
107 static int FE_Delete_Previous(FORM *);
109 /*----------------------------------------------------------------------------
112 Some Remarks on that: I use the convention to use UPPERCASE for constants
113 defined by Macros. If I provide a macro as a kind of inline routine to
114 provide some logic, I use my Upper_Lower case style.
115 --------------------------------------------------------------------------*/
117 /* Calculate the position of a single row in a field buffer */
118 #define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
120 /* Calculate start address for the fields buffer# N */
121 #define Address_Of_Nth_Buffer(field,N) \
122 ((field)->buf + (N)*(1+Buffer_Length(field)))
124 /* Calculate the start address of the row in the fields specified buffer# N */
125 #define Address_Of_Row_In_Nth_Buffer(field,N,row) \
126 (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
128 /* Calculate the start address of the row in the fields primary buffer */
129 #define Address_Of_Row_In_Buffer(field,row) \
130 Address_Of_Row_In_Nth_Buffer(field,0,row)
132 /* Calculate the start address of the row in the forms current field
134 #define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
135 Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
137 /* Calculate the start address of the row in the forms current field
139 #define Address_Of_Current_Row_In_Buffer(form) \
140 Address_Of_Current_Row_In_Nth_Buffer(form,0)
142 /* Calculate the address of the cursor in the forms current field
144 #define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
145 (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
147 /* Calculate the address of the cursor in the forms current field
149 #define Address_Of_Current_Position_In_Buffer(form) \
150 Address_Of_Current_Position_In_Nth_Buffer(form,0)
152 /* Logic to decide wether or not a field is actually a field with
153 vertical or horizontal scrolling */
154 #define Is_Scroll_Field(field) \
155 (((field)->drows > (field)->rows) || \
156 ((field)->dcols > (field)->cols))
158 /* Logic to decide whether or not a field needs to have an individual window
159 instead of a derived window because it contains invisible parts.
160 This is true for non-public fields and for scrollable fields. */
161 #define Has_Invisible_Parts(field) \
162 (!((field)->opts & O_PUBLIC) || \
163 Is_Scroll_Field(field))
165 /* Logic to decide whether or not a field needs justification */
166 #define Justification_Allowed(field) \
167 (((field)->just != NO_JUSTIFICATION) && \
168 (Single_Line_Field(field)) && \
169 (((field)->dcols == (field)->cols) && \
170 ((field)->opts & O_STATIC)) )
172 /* Logic to determine whether or not a dynamic field may still grow */
173 #define Growable(field) ((field)->status & _MAY_GROW)
175 /* Macro to set the attributes for a fields window */
176 #define Set_Field_Window_Attributes(field,win) \
177 ( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
178 wattrset((win),(field)->fore) )
180 /* Logic to decide whether or not a field really appears on the form */
181 #define Field_Really_Appears(field) \
183 (field->form->status & _POSTED) &&\
184 (field->opts & O_VISIBLE) &&\
185 (field->page == field->form->curpage))
187 /* Logic to determine whether or not we are on the first position in the
189 #define First_Position_In_Current_Field(form) \
190 (((form)->currow==0) && ((form)->curcol==0))
193 #define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
194 #define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
196 /*---------------------------------------------------------------------------
197 | Facility : libnform
198 | Function : static char *Get_Start_Of_Data(char * buf, int blen)
200 | Description : Return pointer to first non-blank position in buffer.
201 | If buffer is empty return pointer to buffer itself.
203 | Return Values : Pointer to first non-blank position in buffer
204 +--------------------------------------------------------------------------*/
205 INLINE static char *Get_Start_Of_Data(char * buf, int blen)
208 char *end = &buf[blen];
210 assert(buf && blen>=0);
211 while( (p < end) && is_blank(*p) )
213 return( (p==end) ? buf : p );
216 /*---------------------------------------------------------------------------
217 | Facility : libnform
218 | Function : static char *After_End_Of_Data(char * buf, int blen)
220 | Description : Return pointer after last non-blank position in buffer.
221 | If buffer is empty, return pointer to buffer itself.
223 | Return Values : Pointer to position after last non-blank position in
225 +--------------------------------------------------------------------------*/
226 INLINE static char *After_End_Of_Data(char * buf,int blen)
228 char *p = &buf[blen];
230 assert(buf && blen>=0);
231 while( (p>buf) && is_blank(p[-1]) )
236 /*---------------------------------------------------------------------------
237 | Facility : libnform
238 | Function : static char *Get_First_Whitespace_Character(
239 | char * buf, int blen)
241 | Description : Position to the first whitespace character.
243 | Return Values : Pointer to first whitespace character in buffer.
244 +--------------------------------------------------------------------------*/
245 INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
248 char *end = &p[blen];
250 assert(buf && blen>=0);
251 while( (p < end) && !is_blank(*p))
253 return( (p==end) ? buf : p );
256 /*---------------------------------------------------------------------------
257 | Facility : libnform
258 | Function : static char *After_Last_Whitespace_Character(
259 | char * buf, int blen)
261 | Description : Get the position after the last whitespace character.
263 | Return Values : Pointer to position after last whitespace character in
265 +--------------------------------------------------------------------------*/
266 INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
268 char *p = &buf[blen];
270 assert(buf && blen>=0);
271 while( (p>buf) && !is_blank(p[-1]) )
276 /* Set this to 1 to use the div_t version. This is a good idea if your
277 compiler has an intrinsic div() support. Unfortunately GNU-C has it
279 N.B.: This only works if form->curcol follows immediately form->currow
280 and both are of type int.
282 #define USE_DIV_T (0)
284 /*---------------------------------------------------------------------------
285 | Facility : libnform
286 | Function : static void Adjust_Cursor_Position(
287 | FORM * form, const char * pos)
289 | Description : Set current row and column of the form to values
290 | corresponding to the buffer position.
293 +--------------------------------------------------------------------------*/
294 INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
299 field = form->current;
300 assert( pos >= field->buf && field->dcols > 0);
301 idx = (int)( pos - field->buf );
303 *((div_t *)&(form->currow)) = div(idx,field->dcols);
305 form->currow = idx / field->dcols;
306 form->curcol = idx - field->cols * form->currow;
308 if ( field->drows < form->currow )
312 /*---------------------------------------------------------------------------
313 | Facility : libnform
314 | Function : static void Buffer_To_Window(
315 | const FIELD * field,
318 | Description : Copy the buffer to the window. If its a multiline
319 | field, the buffer is split to the lines of the
320 | window without any editing.
323 +--------------------------------------------------------------------------*/
324 static void Buffer_To_Window(const FIELD * field, WINDOW * win)
331 assert(win && field);
333 width = getmaxx(win);
334 height = getmaxy(win);
336 for(row=0, pBuffer=field->buf;
338 row++, pBuffer += width )
340 if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
342 wmove( win, row, 0 );
343 waddnstr( win, pBuffer, len );
348 /*---------------------------------------------------------------------------
349 | Facility : libnform
350 | Function : static void Window_To_Buffer(
354 | Description : Copy the content of the window into the buffer.
355 | The multiple lines of a window are simply
356 | concatenated into the buffer. Pad characters in
357 | the window will be replaced by blanks in the buffer.
360 +--------------------------------------------------------------------------*/
361 static void Window_To_Buffer(WINDOW * win, FIELD * field)
368 assert(win && field && field->buf );
372 height = getmaxy(win);
374 for(row=0; (row < height) && (row < field->drows); row++ )
376 wmove( win, row, 0 );
377 len += winnstr( win, p+len, field->dcols );
381 /* replace visual padding character by blanks in buffer */
385 for(i=0; i<len; i++, p++)
393 /*---------------------------------------------------------------------------
394 | Facility : libnform
395 | Function : static void Synchronize_Buffer(FORM * form)
397 | Description : If there was a change, copy the content of the
398 | window into the buffer, so the buffer is synchronized
399 | with the windows content. We have to indicate that the
400 | buffer needs validation due to the change.
403 +--------------------------------------------------------------------------*/
404 INLINE static void Synchronize_Buffer(FORM * form)
406 if (form->status & _WINDOW_MODIFIED)
408 form->status &= ~_WINDOW_MODIFIED;
409 form->status |= _FCHECK_REQUIRED;
410 Window_To_Buffer(form->w,form->current);
411 wmove(form->w,form->currow,form->curcol);
415 /*---------------------------------------------------------------------------
416 | Facility : libnform
417 | Function : static bool Field_Grown( FIELD *field, int amount)
419 | Description : This function is called for growable dynamic fields
420 | only. It has to increase the buffers and to allocate
421 | a new window for this field.
422 | This function has the side effect to set a new
423 | field-buffer pointer, the dcols and drows values
424 | as well as a new current Window for the field.
426 | Return Values : TRUE - field successfully increased
427 | FALSE - there was some error
428 +--------------------------------------------------------------------------*/
429 static bool Field_Grown(FIELD * field, int amount)
433 if (field && Growable(field))
435 bool single_line_field = Single_Line_Field(field);
436 int old_buflen = Buffer_Length(field);
438 int old_dcols = field->dcols;
439 int old_drows = field->drows;
440 char *oldbuf = field->buf;
444 FORM *form = field->form;
445 bool need_visual_update = ((form != (FORM *)0) &&
446 (form->status & _POSTED) &&
447 (form->current==field));
449 if (need_visual_update)
450 Synchronize_Buffer(form);
452 if (single_line_field)
454 growth = field->cols * amount;
456 growth = Minimum(field->maxgrow - field->dcols,growth);
457 field->dcols += growth;
458 if (field->dcols == field->maxgrow)
459 field->status &= ~_MAY_GROW;
463 growth = (field->rows + field->nrow) * amount;
465 growth = Minimum(field->maxgrow - field->drows,growth);
466 field->drows += growth;
467 if (field->drows == field->maxgrow)
468 field->status &= ~_MAY_GROW;
470 /* drows, dcols changed, so we get really the new buffer length */
471 new_buflen = Buffer_Length(field);
472 newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
474 { /* restore to previous state */
475 field->dcols = old_dcols;
476 field->drows = old_drows;
477 if (( single_line_field && (field->dcols!=field->maxgrow)) ||
478 (!single_line_field && (field->drows!=field->maxgrow)))
479 field->status |= _MAY_GROW;
483 { /* Copy all the buffers. This is the reason why we can't
491 for(i=0;i<=field->nbuf;i++)
493 new_bp = Address_Of_Nth_Buffer(field,i);
494 old_bp = oldbuf + i*(1+old_buflen);
495 memcpy(new_bp,old_bp,(size_t)old_buflen);
496 if (new_buflen > old_buflen)
497 memset(new_bp + old_buflen,C_BLANK,
498 (size_t)(new_buflen - old_buflen));
499 *(new_bp + new_buflen) = '\0';
502 if (need_visual_update)
504 WINDOW *new_window = newpad(field->drows,field->dcols);
506 { /* restore old state */
507 field->dcols = old_dcols;
508 field->drows = old_drows;
510 if (( single_line_field &&
511 (field->dcols!=field->maxgrow)) ||
512 (!single_line_field &&
513 (field->drows!=field->maxgrow)))
514 field->status |= _MAY_GROW;
518 assert(form!=(FORM *)0);
520 form->w = new_window;
521 Set_Field_Window_Attributes(field,form->w);
523 Buffer_To_Window(field,form->w);
525 wmove(form->w,form->currow,form->curcol);
529 /* reflect changes in linked fields */
530 if (field != field->link)
533 for(linked_field = field->link;
534 linked_field!= field;
535 linked_field = linked_field->link)
537 linked_field->buf = field->buf;
538 linked_field->drows = field->drows;
539 linked_field->dcols = field->dcols;
548 /*---------------------------------------------------------------------------
549 | Facility : libnform
550 | Function : int _nc_Position_Form_Cursor(FORM * form)
552 | Description : Position the cursor in the window for the current
553 | field to be in sync. with the currow and curcol
556 | Return Values : E_OK - success
557 | E_BAD_ARGUMENT - invalid form pointer
558 | E_SYSTEM_ERROR - form has no current field or
560 +--------------------------------------------------------------------------*/
562 _nc_Position_Form_Cursor(FORM * form)
568 return(E_BAD_ARGUMENT);
570 if (!form->w || !form->current)
571 return(E_SYSTEM_ERROR);
573 field = form->current;
574 formwin = Get_Form_Window(form);
576 wmove( form->w, form->currow, form->curcol );
577 if ( Has_Invisible_Parts(field) )
579 /* in this case fieldwin isn't derived from formwin, so we have
580 to move the cursor in formwin by hand... */
582 field->frow + form->currow - form->toprow,
583 field->fcol + form->curcol - form->begincol);
591 /*---------------------------------------------------------------------------
592 | Facility : libnform
593 | Function : int _nc_Refresh_Current_Field(FORM * form)
595 | Description : Propagate the changes in the fields window to the
596 | window of the form.
598 | Return Values : E_OK - on success
599 | E_BAD_ARGUMENT - invalid form pointer
600 | E_SYSTEM_ERROR - general error
601 +--------------------------------------------------------------------------*/
603 _nc_Refresh_Current_Field(FORM * form)
609 RETURN(E_BAD_ARGUMENT);
611 if (!form->w || !form->current)
612 RETURN(E_SYSTEM_ERROR);
614 field = form->current;
615 formwin = Get_Form_Window(form);
617 if (field->opts & O_PUBLIC)
619 if (Is_Scroll_Field(field))
621 /* Again, in this case the fieldwin isn't derived from formwin,
622 so we have to perform a copy operation. */
623 if (Single_Line_Field(field))
624 { /* horizontal scrolling */
625 if (form->curcol < form->begincol)
626 form->begincol = form->curcol;
629 if (form->curcol >= (form->begincol + field->cols))
630 form->begincol = form->curcol - field->cols + 1;
639 field->cols + field->fcol - 1,
643 { /* A multiline, i.e. vertical scrolling field */
644 int row_after_bottom,first_modified_row,first_unmodified_row;
646 if (field->drows > field->rows)
648 row_after_bottom = form->toprow + field->rows;
649 if (form->currow < form->toprow)
651 form->toprow = form->currow;
652 field->status |= _NEWTOP;
654 if (form->currow >= row_after_bottom)
656 form->toprow = form->currow - field->rows + 1;
657 field->status |= _NEWTOP;
659 if (field->status & _NEWTOP)
660 { /* means we have to copy whole range */
661 first_modified_row = form->toprow;
662 first_unmodified_row = first_modified_row + field->rows;
663 field->status &= ~_NEWTOP;
666 { /* we try to optimize : finding the range of touched
668 first_modified_row = form->toprow;
669 while(first_modified_row < row_after_bottom)
671 if (is_linetouched(form->w,first_modified_row))
673 first_modified_row++;
675 first_unmodified_row = first_modified_row;
676 while(first_unmodified_row < row_after_bottom)
678 if (!is_linetouched(form->w,first_unmodified_row))
680 first_unmodified_row++;
686 first_modified_row = form->toprow;
687 first_unmodified_row = first_modified_row + field->rows;
689 if (first_unmodified_row != first_modified_row)
694 field->frow + first_modified_row - form->toprow,
696 field->frow + first_unmodified_row - form->toprow - 1,
697 field->cols + field->fcol - 1,
703 { /* if the field-window is simply a derived window, i.e. contains
704 no invisible parts, the whole thing is trivial
710 return _nc_Position_Form_Cursor(form);
713 /*---------------------------------------------------------------------------
714 | Facility : libnform
715 | Function : static void Perform_Justification(
719 | Description : Output field with requested justification
722 +--------------------------------------------------------------------------*/
723 static void Perform_Justification(FIELD * field, WINDOW * win)
729 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
730 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
734 assert(win && (field->drows == 1) && (field->dcols == field->cols));
741 col = (field->cols - len)/2;
744 col = field->cols - len;
751 waddnstr(win,bp,len);
755 /*---------------------------------------------------------------------------
756 | Facility : libnform
757 | Function : static void Undo_Justification(
761 | Description : Display field without any justification, i.e.
765 +--------------------------------------------------------------------------*/
766 static void Undo_Justification(FIELD * field, WINDOW * win)
771 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
772 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
778 waddnstr(win,bp,len);
782 /*---------------------------------------------------------------------------
783 | Facility : libnform
784 | Function : static bool Check_Char(
787 | TypeArgument *argp)
789 | Description : Perform a single character check for character ch
790 | according to the fieldtype instance.
792 | Return Values : TRUE - Character is valid
793 | FALSE - Character is invalid
794 +--------------------------------------------------------------------------*/
795 static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
799 if (typ->status & _LINKED_TYPE)
803 Check_Char(typ->left ,ch,argp->left ) ||
804 Check_Char(typ->right,ch,argp->right) );
809 return typ->ccheck(ch,(void *)argp);
812 return (isprint((unsigned char)ch) ? TRUE : FALSE);
815 /*---------------------------------------------------------------------------
816 | Facility : libnform
817 | Function : static int Display_Or_Erase_Field(
821 | Description : Create a subwindow for the field and display the
822 | buffer contents (apply justification if required)
823 | or simply erase the field.
825 | Return Values : E_OK - on success
826 | E_SYSTEM_ERROR - some error (typical no memory)
827 +--------------------------------------------------------------------------*/
828 static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
834 return E_SYSTEM_ERROR;
836 fwin = Get_Form_Window(field->form);
838 field->rows,field->cols,field->frow,field->fcol);
841 return E_SYSTEM_ERROR;
844 if (field->opts & O_VISIBLE)
845 Set_Field_Window_Attributes(field,win);
847 wattrset(win,getattrs(fwin));
853 if (field->opts & O_PUBLIC)
855 if (Justification_Allowed(field))
856 Perform_Justification(field,win);
858 Buffer_To_Window(field,win);
860 field->status &= ~_NEWTOP;
867 /* Macros to preset the bEraseFlag */
868 #define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
869 #define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
871 /*---------------------------------------------------------------------------
872 | Facility : libnform
873 | Function : static int Synchronize_Field(FIELD * field)
875 | Description : Synchronize the windows content with the value in
878 | Return Values : E_OK - success
879 | E_BAD_ARGUMENT - invalid field pointer
880 | E_SYSTEM_ERROR - some severe basic error
881 +--------------------------------------------------------------------------*/
882 static int Synchronize_Field(FIELD * field)
888 return(E_BAD_ARGUMENT);
890 if (((form=field->form) != (FORM *)0)
891 && Field_Really_Appears(field))
893 if (field == form->current)
895 form->currow = form->curcol = form->toprow = form->begincol = 0;
898 if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
899 Undo_Justification( field, form->w );
901 Buffer_To_Window( field, form->w );
903 field->status |= _NEWTOP;
904 res = _nc_Refresh_Current_Field( form );
907 res = Display_Field( field );
909 field->status |= _CHANGED;
913 /*---------------------------------------------------------------------------
914 | Facility : libnform
915 | Function : static int Synchronize_Linked_Fields(FIELD * field)
917 | Description : Propagate the Synchronize_Field function to all linked
918 | fields. The first error that occurs in the sequence
919 | of updates is the returnvalue.
921 | Return Values : E_OK - success
922 | E_BAD_ARGUMENT - invalid field pointer
923 | E_SYSTEM_ERROR - some severe basic error
924 +--------------------------------------------------------------------------*/
925 static int Synchronize_Linked_Fields(FIELD * field)
932 return(E_BAD_ARGUMENT);
935 return(E_SYSTEM_ERROR);
937 for(linked_field = field->link;
938 linked_field!= field;
939 linked_field = linked_field->link )
941 if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
948 /*---------------------------------------------------------------------------
949 | Facility : libnform
950 | Function : int _nc_Synchronize_Attributes(FIELD * field)
952 | Description : If a fields visual attributes have changed, this
953 | routine is called to propagate those changes to the
956 | Return Values : E_OK - success
957 | E_BAD_ARGUMENT - invalid field pointer
958 | E_SYSTEM_ERROR - some severe basic error
959 +--------------------------------------------------------------------------*/
960 int _nc_Synchronize_Attributes(FIELD * field)
967 return(E_BAD_ARGUMENT);
969 if (((form=field->form) != (FORM *)0)
970 && Field_Really_Appears(field))
972 if (form->current==field)
974 Synchronize_Buffer(form);
975 Set_Field_Window_Attributes(field,form->w);
977 if (field->opts & O_PUBLIC)
979 if (Justification_Allowed(field))
980 Undo_Justification(field,form->w);
982 Buffer_To_Window(field,form->w);
986 formwin = Get_Form_Window(form);
987 copywin(form->w,formwin,
989 field->frow,field->fcol,
990 field->rows-1,field->cols-1,0);
992 Buffer_To_Window(field,form->w);
993 field->status |= _NEWTOP; /* fake refresh to paint all */
994 _nc_Refresh_Current_Field(form);
999 res = Display_Field(field);
1005 /*---------------------------------------------------------------------------
1006 | Facility : libnform
1007 | Function : int _nc_Synchronize_Options(FIELD * field,
1008 | Field_Options newopts)
1010 | Description : If a fields options have changed, this routine is
1011 | called to propagate these changes to the screen and
1012 | to really change the behaviour of the field.
1014 | Return Values : E_OK - success
1015 | E_BAD_ARGUMENT - invalid field pointer
1016 | E_SYSTEM_ERROR - some severe basic error
1017 +--------------------------------------------------------------------------*/
1019 _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
1021 Field_Options oldopts;
1022 Field_Options changed_opts;
1027 return(E_BAD_ARGUMENT);
1029 oldopts = field->opts;
1030 changed_opts = oldopts ^ newopts;
1031 field->opts = newopts;
1036 if (form->current == field)
1038 field->opts = oldopts;
1042 if (form->status & _POSTED)
1044 if ((form->curpage == field->page))
1046 if (changed_opts & O_VISIBLE)
1048 if (newopts & O_VISIBLE)
1049 res = Display_Field(field);
1051 res = Erase_Field(field);
1055 if ((changed_opts & O_PUBLIC) &&
1056 (newopts & O_VISIBLE))
1057 res = Display_Field(field);
1063 if (changed_opts & O_STATIC)
1065 bool single_line_field = Single_Line_Field(field);
1068 if (newopts & O_STATIC)
1069 { /* the field becomes now static */
1070 field->status &= ~_MAY_GROW;
1071 /* if actually we have no hidden columns, justification may
1073 if (single_line_field &&
1074 (field->cols == field->dcols) &&
1075 (field->just != NO_JUSTIFICATION) &&
1076 Field_Really_Appears(field))
1078 res2 = Display_Field(field);
1082 { /* field is no longer static */
1083 if ((field->maxgrow==0) ||
1084 ( single_line_field && (field->dcols < field->maxgrow)) ||
1085 (!single_line_field && (field->drows < field->maxgrow)))
1087 field->status |= _MAY_GROW;
1088 /* a field with justification now changes its behaviour,
1089 so we must redisplay it */
1090 if (single_line_field &&
1091 (field->just != NO_JUSTIFICATION) &&
1092 Field_Really_Appears(field))
1094 res2 = Display_Field(field);
1105 /*---------------------------------------------------------------------------
1106 | Facility : libnform
1107 | Function : int _nc_Set_Current_Field(FORM * form,
1110 | Description : Make the newfield the new current field.
1112 | Return Values : E_OK - success
1113 | E_BAD_ARGUMENT - invalid form or field pointer
1114 | E_SYSTEM_ERROR - some severe basic error
1115 +--------------------------------------------------------------------------*/
1117 _nc_Set_Current_Field(FORM *form, FIELD *newfield)
1122 if (!form || !newfield || !form->current || (newfield->form!=form))
1123 return(E_BAD_ARGUMENT);
1125 if ( (form->status & _IN_DRIVER) )
1126 return(E_BAD_STATE);
1129 return(E_NOT_CONNECTED);
1131 field = form->current;
1133 if ((field!=newfield) ||
1134 !(form->status & _POSTED))
1137 (field->opts & O_VISIBLE) &&
1138 (field->form->curpage == field->page))
1140 _nc_Refresh_Current_Field(form);
1141 if (field->opts & O_PUBLIC)
1143 if (field->drows > field->rows)
1145 if (form->toprow==0)
1146 field->status &= ~_NEWTOP;
1148 field->status |= _NEWTOP;
1152 if (Justification_Allowed(field))
1154 Window_To_Buffer(form->w,field);
1156 Perform_Justification(field,form->w);
1166 if (Has_Invisible_Parts(field))
1167 new_window = newpad(field->drows,field->dcols);
1169 new_window = derwin(Get_Form_Window(form),
1170 field->rows,field->cols,field->frow,field->fcol);
1173 return(E_SYSTEM_ERROR);
1175 form->current = field;
1176 form->w = new_window;
1177 form->status &= ~_WINDOW_MODIFIED;
1178 Set_Field_Window_Attributes(field,form->w);
1180 if (Has_Invisible_Parts(field))
1183 Buffer_To_Window(field,form->w);
1187 if (Justification_Allowed(field))
1190 Undo_Justification(field,form->w);
1195 untouchwin(form->w);
1198 form->currow = form->curcol = form->toprow = form->begincol = 0;
1202 /*----------------------------------------------------------------------------
1203 Intra-Field Navigation routines
1204 --------------------------------------------------------------------------*/
1206 /*---------------------------------------------------------------------------
1207 | Facility : libnform
1208 | Function : static int IFN_Next_Character(FORM * form)
1210 | Description : Move to the next character in the field. In a multiline
1211 | field this wraps at the end of the line.
1213 | Return Values : E_OK - success
1214 | E_REQUEST_DENIED - at the rightmost position
1215 +--------------------------------------------------------------------------*/
1216 static int IFN_Next_Character(FORM * form)
1218 FIELD *field = form->current;
1220 if ((++(form->curcol))==field->dcols)
1222 if ((++(form->currow))==field->drows)
1224 #if GROW_IF_NAVIGATE
1225 if (!Single_Line_Field(field) && Field_Grown(field,1)) {
1231 #if GROW_IF_NAVIGATE
1232 if (Single_Line_Field(field) && Field_Grown(field,1))
1236 return(E_REQUEST_DENIED);
1243 /*---------------------------------------------------------------------------
1244 | Facility : libnform
1245 | Function : static int IFN_Previous_Character(FORM * form)
1247 | Description : Move to the previous character in the field. In a
1248 | multiline field this wraps and the beginning of the
1251 | Return Values : E_OK - success
1252 | E_REQUEST_DENIED - at the leftmost position
1253 +--------------------------------------------------------------------------*/
1254 static int IFN_Previous_Character(FORM * form)
1256 if ((--(form->curcol))<0)
1258 if ((--(form->currow))<0)
1262 return(E_REQUEST_DENIED);
1264 form->curcol = form->current->dcols - 1;
1269 /*---------------------------------------------------------------------------
1270 | Facility : libnform
1271 | Function : static int IFN_Next_Line(FORM * form)
1273 | Description : Move to the beginning of the next line in the field
1275 | Return Values : E_OK - success
1276 | E_REQUEST_DENIED - at the last line
1277 +--------------------------------------------------------------------------*/
1278 static int IFN_Next_Line(FORM * form)
1280 FIELD *field = form->current;
1282 if ((++(form->currow))==field->drows)
1284 #if GROW_IF_NAVIGATE
1285 if (!Single_Line_Field(field) && Field_Grown(field,1))
1289 return(E_REQUEST_DENIED);
1295 /*---------------------------------------------------------------------------
1296 | Facility : libnform
1297 | Function : static int IFN_Previous_Line(FORM * form)
1299 | Description : Move to the beginning of the previous line in the field
1301 | Return Values : E_OK - success
1302 | E_REQUEST_DENIED - at the first line
1303 +--------------------------------------------------------------------------*/
1304 static int IFN_Previous_Line(FORM * form)
1306 if ( (--(form->currow)) < 0 )
1309 return(E_REQUEST_DENIED);
1315 /*---------------------------------------------------------------------------
1316 | Facility : libnform
1317 | Function : static int IFN_Next_Word(FORM * form)
1319 | Description : Move to the beginning of the next word in the field.
1321 | Return Values : E_OK - success
1322 | E_REQUEST_DENIED - there is no next word
1323 +--------------------------------------------------------------------------*/
1324 static int IFN_Next_Word(FORM * form)
1326 FIELD *field = form->current;
1327 char *bp = Address_Of_Current_Position_In_Buffer(form);
1331 /* We really need access to the data, so we have to synchronize */
1332 Synchronize_Buffer(form);
1334 /* Go to the first whitespace after the current position (including
1335 current position). This is then the startpoint to look for the
1336 next non-blank data */
1337 s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
1338 (int)(bp - field->buf));
1340 /* Find the start of the next word */
1341 t = Get_Start_Of_Data(s,Buffer_Length(field) -
1342 (int)(s - field->buf));
1343 #if !FRIENDLY_PREV_NEXT_WORD
1345 return(E_REQUEST_DENIED);
1349 Adjust_Cursor_Position(form,t);
1354 /*---------------------------------------------------------------------------
1355 | Facility : libnform
1356 | Function : static int IFN_Previous_Word(FORM * form)
1358 | Description : Move to the beginning of the previous word in the field.
1360 | Return Values : E_OK - success
1361 | E_REQUEST_DENIED - there is no previous word
1362 +--------------------------------------------------------------------------*/
1363 static int IFN_Previous_Word(FORM * form)
1365 FIELD *field = form->current;
1366 char *bp = Address_Of_Current_Position_In_Buffer(form);
1371 /* We really need access to the data, so we have to synchronize */
1372 Synchronize_Buffer(form);
1374 s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
1375 /* s points now right after the last non-blank in the buffer before bp.
1376 If bp was in a word, s equals bp. In this case we must find the last
1377 whitespace in the buffer before bp and repeat the game to really find
1378 the previous word! */
1382 /* And next call now goes backward to look for the last whitespace
1383 before that, pointing right after this, so it points to the begin
1384 of the previous word.
1386 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1387 #if !FRIENDLY_PREV_NEXT_WORD
1389 return(E_REQUEST_DENIED);
1392 { /* and do it again, replacing bp by t */
1393 s = After_End_Of_Data(field->buf,(int)(t - field->buf));
1394 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1395 #if !FRIENDLY_PREV_NEXT_WORD
1397 return(E_REQUEST_DENIED);
1400 Adjust_Cursor_Position(form,t);
1404 /*---------------------------------------------------------------------------
1405 | Facility : libnform
1406 | Function : static int IFN_Beginning_Of_Field(FORM * form)
1408 | Description : Place the cursor at the first non-pad character in
1411 | Return Values : E_OK - success
1412 +--------------------------------------------------------------------------*/
1413 static int IFN_Beginning_Of_Field(FORM * form)
1415 FIELD *field = form->current;
1417 Synchronize_Buffer(form);
1418 Adjust_Cursor_Position(form,
1419 Get_Start_Of_Data(field->buf,Buffer_Length(field)));
1423 /*---------------------------------------------------------------------------
1424 | Facility : libnform
1425 | Function : static int IFN_End_Of_Field(FORM * form)
1427 | Description : Place the cursor after the last non-pad character in
1428 | the field. If the field occupies the last position in
1429 | the buffer, the cursos is positioned on the last
1432 | Return Values : E_OK - success
1433 +--------------------------------------------------------------------------*/
1434 static int IFN_End_Of_Field(FORM * form)
1436 FIELD *field = form->current;
1439 Synchronize_Buffer(form);
1440 pos = After_End_Of_Data(field->buf,Buffer_Length(field));
1441 if (pos==(field->buf + Buffer_Length(field)))
1443 Adjust_Cursor_Position(form,pos);
1447 /*---------------------------------------------------------------------------
1448 | Facility : libnform
1449 | Function : static int IFN_Beginning_Of_Line(FORM * form)
1451 | Description : Place the cursor on the first non-pad character in
1452 | the current line of the field.
1454 | Return Values : E_OK - success
1455 +--------------------------------------------------------------------------*/
1456 static int IFN_Beginning_Of_Line(FORM * form)
1458 FIELD *field = form->current;
1460 Synchronize_Buffer(form);
1461 Adjust_Cursor_Position(form,
1462 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1467 /*---------------------------------------------------------------------------
1468 | Facility : libnform
1469 | Function : static int IFN_End_Of_Line(FORM * form)
1471 | Description : Place the cursor after the last non-pad character in the
1472 | current line of the field. If the field occupies the
1473 | last column in the line, the cursor is positioned on the
1474 | last character of the line.
1476 | Return Values : E_OK - success
1477 +--------------------------------------------------------------------------*/
1478 static int IFN_End_Of_Line(FORM * form)
1480 FIELD *field = form->current;
1484 Synchronize_Buffer(form);
1485 bp = Address_Of_Current_Row_In_Buffer(form);
1486 pos = After_End_Of_Data(bp,field->dcols);
1487 if (pos == (bp + field->dcols))
1489 Adjust_Cursor_Position(form,pos);
1493 /*---------------------------------------------------------------------------
1494 | Facility : libnform
1495 | Function : static int IFN_Left_Character(FORM * form)
1497 | Description : Move one character to the left in the current line.
1498 | This doesn't cycle.
1500 | Return Values : E_OK - success
1501 | E_REQUEST_DENIED - already in first column
1502 +--------------------------------------------------------------------------*/
1503 static int IFN_Left_Character(FORM * form)
1505 if ( (--(form->curcol)) < 0 )
1508 return(E_REQUEST_DENIED);
1513 /*---------------------------------------------------------------------------
1514 | Facility : libnform
1515 | Function : static int IFN_Right_Character(FORM * form)
1517 | Description : Move one character to the right in the current line.
1518 | This doesn't cycle.
1520 | Return Values : E_OK - success
1521 | E_REQUEST_DENIED - already in last column
1522 +--------------------------------------------------------------------------*/
1523 static int IFN_Right_Character(FORM * form)
1525 if ( (++(form->curcol)) == form->current->dcols )
1527 #if GROW_IF_NAVIGATE
1528 FIELD *field = form->current;
1529 if (Single_Line_Field(field) && Field_Grown(field,1))
1533 return(E_REQUEST_DENIED);
1538 /*---------------------------------------------------------------------------
1539 | Facility : libnform
1540 | Function : static int IFN_Up_Character(FORM * form)
1542 | Description : Move one line up. This doesn't cycle through the lines
1545 | Return Values : E_OK - success
1546 | E_REQUEST_DENIED - already in last column
1547 +--------------------------------------------------------------------------*/
1548 static int IFN_Up_Character(FORM * form)
1550 if ( (--(form->currow)) < 0 )
1553 return(E_REQUEST_DENIED);
1558 /*---------------------------------------------------------------------------
1559 | Facility : libnform
1560 | Function : static int IFN_Down_Character(FORM * form)
1562 | Description : Move one line down. This doesn't cycle through the
1563 | lines of the field.
1565 | Return Values : E_OK - success
1566 | E_REQUEST_DENIED - already in last column
1567 +--------------------------------------------------------------------------*/
1568 static int IFN_Down_Character(FORM * form)
1570 FIELD *field = form->current;
1572 if ( (++(form->currow)) == field->drows )
1574 #if GROW_IF_NAVIGATE
1575 if (!Single_Line_Field(field) && Field_Grown(field,1))
1579 return(E_REQUEST_DENIED);
1583 /*----------------------------------------------------------------------------
1584 END of Intra-Field Navigation routines
1585 --------------------------------------------------------------------------*/
1587 /*----------------------------------------------------------------------------
1588 Vertical scrolling helper routines
1589 --------------------------------------------------------------------------*/
1591 /*---------------------------------------------------------------------------
1592 | Facility : libnform
1593 | Function : static int VSC_Generic(FORM *form, int lines)
1595 | Description : Scroll multi-line field forward (lines>0) or
1596 | backward (lines<0) this many lines.
1598 | Return Values : E_OK - success
1599 | E_REQUEST_DENIED - can't scroll
1600 +--------------------------------------------------------------------------*/
1601 static int VSC_Generic(FORM *form, int lines)
1603 FIELD *field = form->current;
1604 int res = E_REQUEST_DENIED;
1605 int rows_to_go = (lines > 0 ? lines : -lines);
1609 if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
1610 rows_to_go = (field->drows - field->rows - form->toprow);
1614 form->currow += rows_to_go;
1615 form->toprow += rows_to_go;
1621 if (rows_to_go > form->toprow)
1622 rows_to_go = form->toprow;
1626 form->currow -= rows_to_go;
1627 form->toprow -= rows_to_go;
1633 /*----------------------------------------------------------------------------
1634 End of Vertical scrolling helper routines
1635 --------------------------------------------------------------------------*/
1637 /*----------------------------------------------------------------------------
1638 Vertical scrolling routines
1639 --------------------------------------------------------------------------*/
1641 /*---------------------------------------------------------------------------
1642 | Facility : libnform
1643 | Function : static int Vertical_Scrolling(
1644 | int (* const fct) (FORM *),
1647 | Description : Performs the generic vertical scrolling routines.
1648 | This has to check for a multi-line field and to set
1649 | the _NEWTOP flag if scrolling really occured.
1651 | Return Values : Propagated error code from low-level driver calls
1652 +--------------------------------------------------------------------------*/
1653 static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
1655 int res = E_REQUEST_DENIED;
1657 if (!Single_Line_Field(form->current))
1661 form->current->status |= _NEWTOP;
1666 /*---------------------------------------------------------------------------
1667 | Facility : libnform
1668 | Function : static int VSC_Scroll_Line_Forward(FORM * form)
1670 | Description : Scroll multi-line field forward a line
1672 | Return Values : E_OK - success
1673 | E_REQUEST_DENIED - no data ahead
1674 +--------------------------------------------------------------------------*/
1675 static int VSC_Scroll_Line_Forward(FORM * form)
1677 return VSC_Generic(form,1);
1680 /*---------------------------------------------------------------------------
1681 | Facility : libnform
1682 | Function : static int VSC_Scroll_Line_Backward(FORM * form)
1684 | Description : Scroll multi-line field backward a line
1686 | Return Values : E_OK - success
1687 | E_REQUEST_DENIED - no data behind
1688 +--------------------------------------------------------------------------*/
1689 static int VSC_Scroll_Line_Backward(FORM * form)
1691 return VSC_Generic(form,-1);
1694 /*---------------------------------------------------------------------------
1695 | Facility : libnform
1696 | Function : static int VSC_Scroll_Page_Forward(FORM * form)
1698 | Description : Scroll a multi-line field forward a page
1700 | Return Values : E_OK - success
1701 | E_REQUEST_DENIED - no data ahead
1702 +--------------------------------------------------------------------------*/
1703 static int VSC_Scroll_Page_Forward(FORM * form)
1705 return VSC_Generic(form,form->current->rows);
1708 /*---------------------------------------------------------------------------
1709 | Facility : libnform
1710 | Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1712 | Description : Scroll a multi-line field forward half a page
1714 | Return Values : E_OK - success
1715 | E_REQUEST_DENIED - no data ahead
1716 +--------------------------------------------------------------------------*/
1717 static int VSC_Scroll_Half_Page_Forward(FORM * form)
1719 return VSC_Generic(form,(form->current->rows + 1)/2);
1722 /*---------------------------------------------------------------------------
1723 | Facility : libnform
1724 | Function : static int VSC_Scroll_Page_Backward(FORM * form)
1726 | Description : Scroll a multi-line field backward a page
1728 | Return Values : E_OK - success
1729 | E_REQUEST_DENIED - no data behind
1730 +--------------------------------------------------------------------------*/
1731 static int VSC_Scroll_Page_Backward(FORM * form)
1733 return VSC_Generic(form, -(form->current->rows));
1736 /*---------------------------------------------------------------------------
1737 | Facility : libnform
1738 | Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
1740 | Description : Scroll a multi-line field backward half a page
1742 | Return Values : E_OK - success
1743 | E_REQUEST_DENIED - no data behind
1744 +--------------------------------------------------------------------------*/
1745 static int VSC_Scroll_Half_Page_Backward(FORM * form)
1747 return VSC_Generic(form, -((form->current->rows + 1)/2));
1749 /*----------------------------------------------------------------------------
1750 End of Vertical scrolling routines
1751 --------------------------------------------------------------------------*/
1753 /*----------------------------------------------------------------------------
1754 Horizontal scrolling helper routines
1755 --------------------------------------------------------------------------*/
1757 /*---------------------------------------------------------------------------
1758 | Facility : libnform
1759 | Function : static int HSC_Generic(FORM *form, int columns)
1761 | Description : Scroll single-line field forward (columns>0) or
1762 | backward (columns<0) this many columns.
1764 | Return Values : E_OK - success
1765 | E_REQUEST_DENIED - can't scroll
1766 +--------------------------------------------------------------------------*/
1767 static int HSC_Generic(FORM *form, int columns)
1769 FIELD *field = form->current;
1770 int res = E_REQUEST_DENIED;
1771 int cols_to_go = (columns > 0 ? columns : -columns);
1775 if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
1776 cols_to_go = field->dcols - field->cols - form->begincol;
1780 form->curcol += cols_to_go;
1781 form->begincol += cols_to_go;
1787 if ( cols_to_go > form->begincol )
1788 cols_to_go = form->begincol;
1792 form->curcol -= cols_to_go;
1793 form->begincol -= cols_to_go;
1799 /*----------------------------------------------------------------------------
1800 End of Horizontal scrolling helper routines
1801 --------------------------------------------------------------------------*/
1803 /*----------------------------------------------------------------------------
1804 Horizontal scrolling routines
1805 --------------------------------------------------------------------------*/
1807 /*---------------------------------------------------------------------------
1808 | Facility : libnform
1809 | Function : static int Horizontal_Scrolling(
1810 | int (* const fct) (FORM *),
1813 | Description : Performs the generic horizontal scrolling routines.
1814 | This has to check for a single-line field.
1816 | Return Values : Propagated error code from low-level driver calls
1817 +--------------------------------------------------------------------------*/
1818 static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
1820 if (Single_Line_Field(form->current))
1823 return(E_REQUEST_DENIED);
1826 /*---------------------------------------------------------------------------
1827 | Facility : libnform
1828 | Function : static int HSC_Scroll_Char_Forward(FORM * form)
1830 | Description : Scroll single-line field forward a character
1832 | Return Values : E_OK - success
1833 | E_REQUEST_DENIED - no data ahead
1834 +--------------------------------------------------------------------------*/
1835 static int HSC_Scroll_Char_Forward(FORM *form)
1837 return HSC_Generic(form,1);
1840 /*---------------------------------------------------------------------------
1841 | Facility : libnform
1842 | Function : static int HSC_Scroll_Char_Backward(FORM * form)
1844 | Description : Scroll single-line field backward a character
1846 | Return Values : E_OK - success
1847 | E_REQUEST_DENIED - no data behind
1848 +--------------------------------------------------------------------------*/
1849 static int HSC_Scroll_Char_Backward(FORM *form)
1851 return HSC_Generic(form,-1);
1854 /*---------------------------------------------------------------------------
1855 | Facility : libnform
1856 | Function : static int HSC_Horizontal_Line_Forward(FORM* form)
1858 | Description : Scroll single-line field forward a line
1860 | Return Values : E_OK - success
1861 | E_REQUEST_DENIED - no data ahead
1862 +--------------------------------------------------------------------------*/
1863 static int HSC_Horizontal_Line_Forward(FORM * form)
1865 return HSC_Generic(form,form->current->cols);
1868 /*---------------------------------------------------------------------------
1869 | Facility : libnform
1870 | Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
1872 | Description : Scroll single-line field forward half a line
1874 | Return Values : E_OK - success
1875 | E_REQUEST_DENIED - no data ahead
1876 +--------------------------------------------------------------------------*/
1877 static int HSC_Horizontal_Half_Line_Forward(FORM * form)
1879 return HSC_Generic(form,(form->current->cols + 1)/2);
1882 /*---------------------------------------------------------------------------
1883 | Facility : libnform
1884 | Function : static int HSC_Horizontal_Line_Backward(FORM* form)
1886 | Description : Scroll single-line field backward a line
1888 | Return Values : E_OK - success
1889 | E_REQUEST_DENIED - no data behind
1890 +--------------------------------------------------------------------------*/
1891 static int HSC_Horizontal_Line_Backward(FORM * form)
1893 return HSC_Generic(form,-(form->current->cols));
1896 /*---------------------------------------------------------------------------
1897 | Facility : libnform
1898 | Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
1900 | Description : Scroll single-line field backward half a line
1902 | Return Values : E_OK - success
1903 | E_REQUEST_DENIED - no data behind
1904 +--------------------------------------------------------------------------*/
1905 static int HSC_Horizontal_Half_Line_Backward(FORM * form)
1907 return HSC_Generic(form,-((form->current->cols + 1)/2));
1910 /*----------------------------------------------------------------------------
1911 End of Horizontal scrolling routines
1912 --------------------------------------------------------------------------*/
1914 /*----------------------------------------------------------------------------
1915 Helper routines for Field Editing
1916 --------------------------------------------------------------------------*/
1918 /*---------------------------------------------------------------------------
1919 | Facility : libnform
1920 | Function : static bool Is_There_Room_For_A_Line(FORM * form)
1922 | Description : Check whether or not there is enough room in the
1923 | buffer to enter a whole line.
1925 | Return Values : TRUE - there is enough space
1926 | FALSE - there is not enough space
1927 +--------------------------------------------------------------------------*/
1928 INLINE static bool Is_There_Room_For_A_Line(FORM * form)
1930 FIELD *field = form->current;
1931 char *begin_of_last_line, *s;
1933 Synchronize_Buffer(form);
1934 begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
1935 s = After_End_Of_Data(begin_of_last_line,field->dcols);
1936 return ((s==begin_of_last_line) ? TRUE : FALSE);
1939 /*---------------------------------------------------------------------------
1940 | Facility : libnform
1941 | Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1943 | Description : Checks whether or not there is room for a new character
1944 | in the current line.
1946 | Return Values : TRUE - there is room
1947 | FALSE - there is not enough room (line full)
1948 +--------------------------------------------------------------------------*/
1949 INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1951 int last_char_in_line;
1953 wmove(form->w,form->currow,form->current->dcols-1);
1954 last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
1955 wmove(form->w,form->currow,form->curcol);
1956 return (((last_char_in_line == form->current->pad) ||
1957 is_blank(last_char_in_line)) ? TRUE : FALSE);
1960 #define There_Is_No_Room_For_A_Char_In_Line(f) \
1961 !Is_There_Room_For_A_Char_In_Line(f)
1963 /*---------------------------------------------------------------------------
1964 | Facility : libnform
1965 | Function : static int Insert_String(
1971 | Description : Insert the 'len' characters beginning at pointer 'txt'
1972 | into the 'row' of the 'form'. The insertion occurs
1973 | on the beginning of the row, all other characters are
1974 | moved to the right. After the text a pad character will
1975 | be inserted to separate the text from the rest. If
1976 | necessary the insertion moves characters on the next
1977 | line to make place for the requested insertion string.
1979 | Return Values : E_OK - success
1980 | E_REQUEST_DENIED -
1981 | E_SYSTEM_ERROR - system error
1982 +--------------------------------------------------------------------------*/
1983 static int Insert_String(FORM *form, int row, char *txt, int len)
1985 FIELD *field = form->current;
1986 char *bp = Address_Of_Row_In_Buffer(field,row);
1987 int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
1988 int freelen = field->dcols - datalen;
1989 int requiredlen = len+1;
1991 int result = E_REQUEST_DENIED;
1992 const char *Space = " ";
1994 if (freelen >= requiredlen)
1996 wmove(form->w,row,0);
1997 winsnstr(form->w,txt,len);
1998 wmove(form->w,row,len);
1999 winsnstr(form->w,Space,1);
2003 { /* we have to move characters on the next line. If we are on the
2004 last line this may work, if the field is growable */
2005 if ((row == (field->drows - 1)) && Growable(field))
2007 if (!Field_Grown(field,1))
2008 return(E_SYSTEM_ERROR);
2009 /* !!!Side-Effect : might be changed due to growth!!! */
2010 bp = Address_Of_Row_In_Buffer(field,row);
2013 if (row < (field->drows - 1))
2015 split = After_Last_Whitespace_Character(bp,
2016 (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
2017 requiredlen) - bp));
2018 /* split points now to the first character of the portion of the
2019 line that must be moved to the next line */
2020 datalen = (int)(split-bp); /* + freelen has to stay on this line */
2021 freelen = field->dcols - (datalen + freelen); /* for the next line */
2023 if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
2025 wmove(form->w,row,datalen);
2027 wmove(form->w,row,0);
2028 winsnstr(form->w,txt,len);
2029 wmove(form->w,row,len);
2030 winsnstr(form->w,Space,1);
2038 /*---------------------------------------------------------------------------
2039 | Facility : libnform
2040 | Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2043 | Description : If a character has been entered into a field, it may
2044 | be that wrapping has to occur. This routine checks
2045 | whether or not wrapping is required and if so, performs
2048 | Return Values : E_OK - no wrapping required or wrapping
2050 | E_REQUEST_DENIED -
2051 | E_SYSTEM_ERROR - some system error
2052 +--------------------------------------------------------------------------*/
2053 static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
2055 FIELD *field = form->current;
2056 int result = E_REQUEST_DENIED;
2057 bool Last_Row = ((field->drows - 1) == form->currow);
2059 if ( (field->opts & O_WRAP) && /* wrapping wanted */
2060 (!Single_Line_Field(field)) && /* must be multi-line */
2061 (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
2062 (!Last_Row || Growable(field)) ) /* there are more lines*/
2066 int chars_to_be_wrapped;
2067 int chars_to_remain_on_line;
2069 { /* the above logic already ensures, that in this case the field
2071 if (!Field_Grown(field,1))
2072 return E_SYSTEM_ERROR;
2074 bp = Address_Of_Current_Row_In_Buffer(form);
2075 Window_To_Buffer(form->w,field);
2076 split = After_Last_Whitespace_Character(bp,field->dcols);
2077 /* split points to the first character of the sequence to be brought
2079 chars_to_remain_on_line = (int)(split - bp);
2080 chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2081 if (chars_to_remain_on_line > 0)
2083 if ((result=Insert_String(form,form->currow+1,split,
2084 chars_to_be_wrapped)) == E_OK)
2086 wmove(form->w,form->currow,chars_to_remain_on_line);
2088 if (form->curcol >= chars_to_remain_on_line)
2091 form->curcol -= chars_to_remain_on_line;
2100 wmove(form->w,form->currow,form->curcol);
2102 Window_To_Buffer(form->w,field);
2103 result = E_REQUEST_DENIED;
2107 result = E_OK; /* wrapping was not necessary */
2111 /*----------------------------------------------------------------------------
2112 Field Editing routines
2113 --------------------------------------------------------------------------*/
2115 /*---------------------------------------------------------------------------
2116 | Facility : libnform
2117 | Function : static int Field_Editing(
2118 | int (* const fct) (FORM *),
2121 | Description : Generic routine for field editing requests. The driver
2122 | routines are only called for editable fields, the
2123 | _WINDOW_MODIFIED flag is set if editing occured.
2124 | This is somewhat special due to the overload semantics
2125 | of the NEW_LINE and DEL_PREV requests.
2127 | Return Values : Error code from low level drivers.
2128 +--------------------------------------------------------------------------*/
2129 static int Field_Editing(int (* const fct) (FORM *), FORM * form)
2131 int res = E_REQUEST_DENIED;
2133 /* We have to deal here with the specific case of the overloaded
2134 behaviour of New_Line and Delete_Previous requests.
2135 They may end up in navigational requests if we are on the first
2136 character in a field. But navigation is also allowed on non-
2139 if ((fct==FE_Delete_Previous) &&
2140 (form->opts & O_BS_OVERLOAD) &&
2141 First_Position_In_Current_Field(form) )
2143 res = Inter_Field_Navigation(FN_Previous_Field,form);
2147 if (fct==FE_New_Line)
2149 if ((form->opts & O_NL_OVERLOAD) &&
2150 First_Position_In_Current_Field(form))
2152 res = Inter_Field_Navigation(FN_Next_Field,form);
2155 /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2160 /* From now on, everything must be editable */
2161 if (form->current->opts & O_EDIT)
2165 form->status |= _WINDOW_MODIFIED;
2172 /*---------------------------------------------------------------------------
2173 | Facility : libnform
2174 | Function : static int FE_New_Line(FORM * form)
2176 | Description : Perform a new line request. This is rather complex
2177 | compared to other routines in this code due to the
2178 | rather difficult to understand description in the
2181 | Return Values : E_OK - success
2182 | E_REQUEST_DENIED - new line not allowed
2183 | E_SYSTEM_ERROR - system error
2184 +--------------------------------------------------------------------------*/
2185 static int FE_New_Line(FORM * form)
2187 FIELD *field = form->current;
2189 bool Last_Row = ((field->drows - 1)==form->currow);
2191 if (form->status & _OVLMODE)
2194 (!(Growable(field) && !Single_Line_Field(field))))
2196 if (!(form->opts & O_NL_OVERLOAD))
2197 return(E_REQUEST_DENIED);
2199 /* we have to set this here, although it is also
2200 handled in the generic routine. The reason is,
2201 that FN_Next_Field may fail, but the form is
2202 definitively changed */
2203 form->status |= _WINDOW_MODIFIED;
2204 return Inter_Field_Navigation(FN_Next_Field,form);
2208 if (Last_Row && !Field_Grown(field,1))
2209 { /* N.B.: due to the logic in the 'if', LastRow==TRUE
2210 means here that the field is growable and not
2211 a single-line field */
2212 return(E_SYSTEM_ERROR);
2217 form->status |= _WINDOW_MODIFIED;
2224 !(Growable(field) && !Single_Line_Field(field)))
2226 if (!(form->opts & O_NL_OVERLOAD))
2227 return(E_REQUEST_DENIED);
2228 return Inter_Field_Navigation(FN_Next_Field,form);
2232 bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2234 if (!(May_Do_It || Growable(field)))
2235 return(E_REQUEST_DENIED);
2236 if (!May_Do_It && !Field_Grown(field,1))
2237 return(E_SYSTEM_ERROR);
2239 bp= Address_Of_Current_Position_In_Buffer(form);
2240 t = After_End_Of_Data(bp,field->dcols - form->curcol);
2244 wmove(form->w,form->currow,form->curcol);
2246 waddnstr(form->w,bp,(int)(t-bp));
2247 form->status |= _WINDOW_MODIFIED;
2253 /*---------------------------------------------------------------------------
2254 | Facility : libnform
2255 | Function : static int FE_Insert_Character(FORM * form)
2257 | Description : Insert blank character at the cursor position
2259 | Return Values : E_OK
2261 +--------------------------------------------------------------------------*/
2262 static int FE_Insert_Character(FORM * form)
2264 FIELD *field = form->current;
2265 int result = E_REQUEST_DENIED;
2267 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2269 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2271 if (There_Is_Room ||
2272 ((Single_Line_Field(field) && Growable(field))))
2274 if (!There_Is_Room && !Field_Grown(field,1))
2275 result = E_SYSTEM_ERROR;
2278 winsch(form->w,(chtype)C_BLANK);
2279 result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2286 /*---------------------------------------------------------------------------
2287 | Facility : libnform
2288 | Function : static int FE_Insert_Line(FORM * form)
2290 | Description : Insert a blank line at the cursor position
2292 | Return Values : E_OK - success
2293 | E_REQUEST_DENIED - line can not be inserted
2294 +--------------------------------------------------------------------------*/
2295 static int FE_Insert_Line(FORM * form)
2297 FIELD *field = form->current;
2298 int result = E_REQUEST_DENIED;
2300 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2302 bool Maybe_Done = (form->currow!=(field->drows-1)) &&
2303 Is_There_Room_For_A_Line(form);
2305 if (!Single_Line_Field(field) &&
2306 (Maybe_Done || Growable(field)))
2308 if (!Maybe_Done && !Field_Grown(field,1))
2309 result = E_SYSTEM_ERROR;
2321 /*---------------------------------------------------------------------------
2322 | Facility : libnform
2323 | Function : static int FE_Delete_Character(FORM * form)
2325 | Description : Delete character at the cursor position
2327 | Return Values : E_OK - success
2328 +--------------------------------------------------------------------------*/
2329 static int FE_Delete_Character(FORM * form)
2335 /*---------------------------------------------------------------------------
2336 | Facility : libnform
2337 | Function : static int FE_Delete_Previous(FORM * form)
2339 | Description : Delete character before cursor. Again this is a rather
2340 | difficult piece compared to others due to the overloading
2341 | semantics of backspace.
2342 | N.B.: The case of overloaded BS on first field position
2343 | is already handled in the generic routine.
2345 | Return Values : E_OK - success
2346 | E_REQUEST_DENIED - Character can't be deleted
2347 +--------------------------------------------------------------------------*/
2348 static int FE_Delete_Previous(FORM * form)
2350 FIELD *field = form->current;
2352 if (First_Position_In_Current_Field(form))
2353 return E_REQUEST_DENIED;
2355 if ( (--(form->curcol))<0 )
2357 char *this_line, *prev_line, *prev_end, *this_end;
2360 if (form->status & _OVLMODE)
2361 return E_REQUEST_DENIED;
2363 prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
2364 this_line = Address_Of_Row_In_Buffer(field,(form->currow));
2365 Synchronize_Buffer(form);
2366 prev_end = After_End_Of_Data(prev_line,field->dcols);
2367 this_end = After_End_Of_Data(this_line,field->dcols);
2368 if ((int)(this_end-this_line) >
2369 (field->cols-(int)(prev_end-prev_line)))
2370 return E_REQUEST_DENIED;
2372 Adjust_Cursor_Position(form,prev_end);
2373 wmove(form->w,form->currow,form->curcol);
2374 waddnstr(form->w,this_line,(int)(this_end-this_line));
2378 wmove(form->w,form->currow,form->curcol);
2384 /*---------------------------------------------------------------------------
2385 | Facility : libnform
2386 | Function : static int FE_Delete_Line(FORM * form)
2388 | Description : Delete line at cursor position.
2390 | Return Values : E_OK - success
2391 +--------------------------------------------------------------------------*/
2392 static int FE_Delete_Line(FORM * form)
2399 /*---------------------------------------------------------------------------
2400 | Facility : libnform
2401 | Function : static int FE_Delete_Word(FORM * form)
2403 | Description : Delete word at cursor position
2405 | Return Values : E_OK - success
2406 | E_REQUEST_DENIED - failure
2407 +--------------------------------------------------------------------------*/
2408 static int FE_Delete_Word(FORM * form)
2410 FIELD *field = form->current;
2411 char *bp = Address_Of_Current_Row_In_Buffer(form);
2412 char *ep = bp + field->dcols;
2413 char *cp = bp + form->curcol;
2416 Synchronize_Buffer(form);
2418 return E_REQUEST_DENIED; /* not in word */
2420 /* move cursor to begin of word and erase to end of screen-line */
2421 Adjust_Cursor_Position(form,
2422 After_Last_Whitespace_Character(bp,form->curcol));
2423 wmove(form->w,form->currow,form->curcol);
2426 /* skip over word in buffer */
2427 s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
2428 /* to begin of next word */
2429 s = Get_Start_Of_Data(s,(int)(ep - s));
2430 if ( (s!=cp) && !is_blank(*s))
2432 /* copy remaining line to window */
2433 waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
2438 /*---------------------------------------------------------------------------
2439 | Facility : libnform
2440 | Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2442 | Description : Clear to end of current line.
2444 | Return Values : E_OK - success
2445 +--------------------------------------------------------------------------*/
2446 static int FE_Clear_To_End_Of_Line(FORM * form)
2452 /*---------------------------------------------------------------------------
2453 | Facility : libnform
2454 | Function : static int FE_Clear_To_End_Of_Form(FORM * form)
2456 | Description : Clear to end of form.
2458 | Return Values : E_OK - success
2459 +--------------------------------------------------------------------------*/
2460 static int FE_Clear_To_End_Of_Form(FORM * form)
2466 /*---------------------------------------------------------------------------
2467 | Facility : libnform
2468 | Function : static int FE_Clear_Field(FORM * form)
2470 | Description : Clear entire field.
2472 | Return Values : E_OK - success
2473 +--------------------------------------------------------------------------*/
2474 static int FE_Clear_Field(FORM * form)
2476 form->currow = form->curcol = 0;
2480 /*----------------------------------------------------------------------------
2481 END of Field Editing routines
2482 --------------------------------------------------------------------------*/
2484 /*----------------------------------------------------------------------------
2486 --------------------------------------------------------------------------*/
2488 /*---------------------------------------------------------------------------
2489 | Facility : libnform
2490 | Function : static int EM_Overlay_Mode(FORM * form)
2492 | Description : Switch to overlay mode.
2494 | Return Values : E_OK - success
2495 +--------------------------------------------------------------------------*/
2496 static int EM_Overlay_Mode(FORM * form)
2498 form->status |= _OVLMODE;
2502 /*---------------------------------------------------------------------------
2503 | Facility : libnform
2504 | Function : static int EM_Insert_Mode(FORM * form)
2506 | Description : Switch to insert mode
2508 | Return Values : E_OK - success
2509 +--------------------------------------------------------------------------*/
2510 static int EM_Insert_Mode(FORM * form)
2512 form->status &= ~_OVLMODE;
2516 /*----------------------------------------------------------------------------
2517 END of Edit Mode routines
2518 --------------------------------------------------------------------------*/
2520 /*----------------------------------------------------------------------------
2521 Helper routines for Choice Requests
2522 --------------------------------------------------------------------------*/
2524 /*---------------------------------------------------------------------------
2525 | Facility : libnform
2526 | Function : static bool Next_Choice(
2529 | TypeArgument *argp)
2531 | Description : Get the next field choice. For linked types this is
2534 | Return Values : TRUE - next choice successfully retrieved
2535 | FALSE - couldn't retrieve next choice
2536 +--------------------------------------------------------------------------*/
2537 static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
2539 if (!typ || !(typ->status & _HAS_CHOICE))
2542 if (typ->status & _LINKED_TYPE)
2546 Next_Choice(typ->left ,field,argp->left) ||
2547 Next_Choice(typ->right,field,argp->right) );
2552 return typ->next(field,(void *)argp);
2556 /*---------------------------------------------------------------------------
2557 | Facility : libnform
2558 | Function : static bool Previous_Choice(
2561 | TypeArgument *argp)
2563 | Description : Get the previous field choice. For linked types this
2564 | is done recursively.
2566 | Return Values : TRUE - previous choice successfully retrieved
2567 | FALSE - couldn't retrieve previous choice
2568 +--------------------------------------------------------------------------*/
2569 static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2571 if (!typ || !(typ->status & _HAS_CHOICE))
2574 if (typ->status & _LINKED_TYPE)
2578 Previous_Choice(typ->left ,field,argp->left) ||
2579 Previous_Choice(typ->right,field,argp->right));
2584 return typ->prev(field,(void *)argp);
2587 /*----------------------------------------------------------------------------
2588 End of Helper routines for Choice Requests
2589 --------------------------------------------------------------------------*/
2591 /*----------------------------------------------------------------------------
2592 Routines for Choice Requests
2593 --------------------------------------------------------------------------*/
2595 /*---------------------------------------------------------------------------
2596 | Facility : libnform
2597 | Function : static int CR_Next_Choice(FORM * form)
2599 | Description : Get the next field choice.
2601 | Return Values : E_OK - success
2602 | E_REQUEST_DENIED - next choice couldn't be retrieved
2603 +--------------------------------------------------------------------------*/
2604 static int CR_Next_Choice(FORM * form)
2606 FIELD *field = form->current;
2607 Synchronize_Buffer(form);
2608 return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2609 E_OK : E_REQUEST_DENIED);
2612 /*---------------------------------------------------------------------------
2613 | Facility : libnform
2614 | Function : static int CR_Previous_Choice(FORM * form)
2616 | Description : Get the previous field choice.
2618 | Return Values : E_OK - success
2619 | E_REQUEST_DENIED - prev. choice couldn't be retrieved
2620 +--------------------------------------------------------------------------*/
2621 static int CR_Previous_Choice(FORM * form)
2623 FIELD *field = form->current;
2624 Synchronize_Buffer(form);
2625 return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2626 E_OK : E_REQUEST_DENIED);
2628 /*----------------------------------------------------------------------------
2629 End of Routines for Choice Requests
2630 --------------------------------------------------------------------------*/
2632 /*----------------------------------------------------------------------------
2633 Helper routines for Field Validations.
2634 --------------------------------------------------------------------------*/
2636 /*---------------------------------------------------------------------------
2637 | Facility : libnform
2638 | Function : static bool Check_Field(
2641 | TypeArgument * argp)
2643 | Description : Check the field according to its fieldtype and its
2644 | actual arguments. For linked fieldtypes this is done
2647 | Return Values : TRUE - field is valid
2648 | FALSE - field is invalid.
2649 +--------------------------------------------------------------------------*/
2650 static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2654 if (field->opts & O_NULLOK)
2656 char *bp = field->buf;
2658 while(is_blank(*bp))
2664 if (typ->status & _LINKED_TYPE)
2668 Check_Field(typ->left ,field,argp->left ) ||
2669 Check_Field(typ->right,field,argp->right) );
2674 return typ->fcheck(field,(void *)argp);
2680 /*---------------------------------------------------------------------------
2681 | Facility : libnform
2682 | Function : bool _nc_Internal_Validation(FORM * form )
2684 | Description : Validate the current field of the form.
2686 | Return Values : TRUE - field is valid
2687 | FALSE - field is invalid
2688 +--------------------------------------------------------------------------*/
2690 _nc_Internal_Validation(FORM *form)
2694 field = form->current;
2696 Synchronize_Buffer(form);
2697 if ((form->status & _FCHECK_REQUIRED) ||
2698 (!(field->opts & O_PASSOK)))
2700 if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
2702 form->status &= ~_FCHECK_REQUIRED;
2703 field->status |= _CHANGED;
2704 Synchronize_Linked_Fields(field);
2708 /*----------------------------------------------------------------------------
2709 End of Helper routines for Field Validations.
2710 --------------------------------------------------------------------------*/
2712 /*----------------------------------------------------------------------------
2713 Routines for Field Validation.
2714 --------------------------------------------------------------------------*/
2716 /*---------------------------------------------------------------------------
2717 | Facility : libnform
2718 | Function : static int FV_Validation(FORM * form)
2720 | Description : Validate the current field of the form.
2722 | Return Values : E_OK - field valid
2723 | E_INVALID_FIELD - field not valid
2724 +--------------------------------------------------------------------------*/
2725 static int FV_Validation(FORM * form)
2727 if (_nc_Internal_Validation(form))
2730 return E_INVALID_FIELD;
2732 /*----------------------------------------------------------------------------
2733 End of routines for Field Validation.
2734 --------------------------------------------------------------------------*/
2736 /*----------------------------------------------------------------------------
2737 Helper routines for Inter-Field Navigation
2738 --------------------------------------------------------------------------*/
2740 /*---------------------------------------------------------------------------
2741 | Facility : libnform
2742 | Function : static FIELD *Next_Field_On_Page(FIELD * field)
2744 | Description : Get the next field after the given field on the current
2745 | page. The order of fields is the one defined by the
2746 | fields array. Only visible and active fields are
2749 | Return Values : Pointer to the next field.
2750 +--------------------------------------------------------------------------*/
2751 INLINE static FIELD *Next_Field_On_Page(FIELD * field)
2753 FORM *form = field->form;
2754 FIELD **field_on_page = &form->field[field->index];
2755 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2756 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2761 (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
2762 if (Field_Is_Selectable(*field_on_page))
2764 } while(field!=(*field_on_page));
2765 return(*field_on_page);
2768 /*---------------------------------------------------------------------------
2769 | Facility : libnform
2770 | Function : FIELD* _nc_First_Active_Field(FORM * form)
2772 | Description : Get the first active field on the current page,
2773 | if there are such. If there are none, get the first
2774 | visible field on the page. If there are also none,
2775 | we return the first field on page and hope the best.
2777 | Return Values : Pointer to calculated field.
2778 +--------------------------------------------------------------------------*/
2780 _nc_First_Active_Field(FORM * form)
2782 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2783 FIELD *proposed = Next_Field_On_Page(*last_on_page);
2785 if (proposed == *last_on_page)
2786 { /* there might be the special situation, where there is no
2787 active and visible field on the current page. We then select
2788 the first visible field on this readonly page
2790 if (Field_Is_Not_Selectable(proposed))
2792 FIELD **field = &form->field[proposed->index];
2793 FIELD **first = &form->field[form->page[form->curpage].pmin];
2797 field = (field==last_on_page) ? first : field + 1;
2798 if (((*field)->opts & O_VISIBLE))
2800 } while(proposed!=(*field));
2804 if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
2805 { /* This means, there is also no visible field on the page.
2806 So we propose the first one and hope the very best...
2807 Some very clever user has designed a readonly and invisible
2817 /*---------------------------------------------------------------------------
2818 | Facility : libnform
2819 | Function : static FIELD *Previous_Field_On_Page(FIELD * field)
2821 | Description : Get the previous field before the given field on the
2822 | current page. The order of fields is the one defined by
2823 | the fields array. Only visible and active fields are
2826 | Return Values : Pointer to the previous field.
2827 +--------------------------------------------------------------------------*/
2828 INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
2830 FORM *form = field->form;
2831 FIELD **field_on_page = &form->field[field->index];
2832 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2833 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2838 (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
2839 if (Field_Is_Selectable(*field_on_page))
2841 } while(field!=(*field_on_page));
2843 return (*field_on_page);
2846 /*---------------------------------------------------------------------------
2847 | Facility : libnform
2848 | Function : static FIELD *Sorted_Next_Field(FIELD * field)
2850 | Description : Get the next field after the given field on the current
2851 | page. The order of fields is the one defined by the
2852 | (row,column) geometry, rows are major.
2854 | Return Values : Pointer to the next field.
2855 +--------------------------------------------------------------------------*/
2856 INLINE static FIELD *Sorted_Next_Field(FIELD * field)
2858 FIELD *field_on_page = field;
2862 field_on_page = field_on_page->snext;
2863 if (Field_Is_Selectable(field_on_page))
2865 } while(field_on_page!=field);
2867 return (field_on_page);
2870 /*---------------------------------------------------------------------------
2871 | Facility : libnform
2872 | Function : static FIELD *Sorted_Previous_Field(FIELD * field)
2874 | Description : Get the previous field before the given field on the
2875 | current page. The order of fields is the one defined
2876 | by the (row,column) geometry, rows are major.
2878 | Return Values : Pointer to the previous field.
2879 +--------------------------------------------------------------------------*/
2880 INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
2882 FIELD *field_on_page = field;
2886 field_on_page = field_on_page->sprev;
2887 if (Field_Is_Selectable(field_on_page))
2889 } while(field_on_page!=field);
2891 return (field_on_page);
2894 /*---------------------------------------------------------------------------
2895 | Facility : libnform
2896 | Function : static FIELD *Left_Neighbour_Field(FIELD * field)
2898 | Description : Get the left neighbour of the field on the same line
2899 | and the same page. Cycles through the line.
2901 | Return Values : Pointer to left neighbour field.
2902 +--------------------------------------------------------------------------*/
2903 INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
2905 FIELD *field_on_page = field;
2907 /* For a field that has really a left neighbour, the while clause
2908 immediately fails and the loop is left, positioned at the right
2909 neighbour. Otherwise we cycle backwards through the sorted fieldlist
2910 until we enter the same line (from the right end).
2914 field_on_page = Sorted_Previous_Field(field_on_page);
2915 } while(field_on_page->frow != field->frow);
2917 return (field_on_page);
2920 /*---------------------------------------------------------------------------
2921 | Facility : libnform
2922 | Function : static FIELD *Right_Neighbour_Field(FIELD * field)
2924 | Description : Get the right neighbour of the field on the same line
2925 | and the same page.
2927 | Return Values : Pointer to right neighbour field.
2928 +--------------------------------------------------------------------------*/
2929 INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
2931 FIELD *field_on_page = field;
2933 /* See the comments on Left_Neighbour_Field to understand how it works */
2936 field_on_page = Sorted_Next_Field(field_on_page);
2937 } while(field_on_page->frow != field->frow);
2939 return (field_on_page);
2942 /*---------------------------------------------------------------------------
2943 | Facility : libnform
2944 | Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
2946 | Description : Because of the row-major nature of sorting the fields,
2947 | its more difficult to define whats the upper neighbour
2948 | field really means. We define that it must be on a
2949 | 'previous' line (cyclic order!) and is the rightmost
2950 | field laying on the left side of the given field. If
2951 | this set is empty, we take the first field on the line.
2953 | Return Values : Pointer to the upper neighbour field.
2954 +--------------------------------------------------------------------------*/
2955 static FIELD *Upper_Neighbour_Field(FIELD * field)
2957 FIELD *field_on_page = field;
2958 int frow = field->frow;
2959 int fcol = field->fcol;
2961 /* Walk back to the 'previous' line. The second term in the while clause
2962 just guarantees that we stop if we cycled through the line because
2963 there might be no 'previous' line if the page has just one line.
2967 field_on_page = Sorted_Previous_Field(field_on_page);
2968 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
2970 if (field_on_page->frow!=frow)
2971 { /* We really found a 'previous' line. We are positioned at the
2972 rightmost field on this line */
2973 frow = field_on_page->frow;
2975 /* We walk to the left as long as we are really right of the
2977 while(field_on_page->frow==frow && field_on_page->fcol>fcol)
2978 field_on_page = Sorted_Previous_Field(field_on_page);
2980 /* If we wrapped, just go to the right which is the first field on
2982 if (field_on_page->frow!=frow)
2983 field_on_page = Sorted_Next_Field(field_on_page);
2986 return (field_on_page);
2989 /*---------------------------------------------------------------------------
2990 | Facility : libnform
2991 | Function : static FIELD *Down_Neighbour_Field(FIELD * field)
2993 | Description : Because of the row-major nature of sorting the fields,
2994 | its more difficult to define whats the down neighbour
2995 | field really means. We define that it must be on a
2996 | 'next' line (cyclic order!) and is the leftmost
2997 | field laying on the right side of the given field. If
2998 | this set is empty, we take the last field on the line.
3000 | Return Values : Pointer to the upper neighbour field.
3001 +--------------------------------------------------------------------------*/
3002 static FIELD *Down_Neighbour_Field(FIELD * field)
3004 FIELD *field_on_page = field;
3005 int frow = field->frow;
3006 int fcol = field->fcol;
3008 /* Walk forward to the 'next' line. The second term in the while clause
3009 just guarantees that we stop if we cycled through the line because
3010 there might be no 'next' line if the page has just one line.
3014 field_on_page = Sorted_Next_Field(field_on_page);
3015 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3017 if (field_on_page->frow!=frow)
3018 { /* We really found a 'next' line. We are positioned at the rightmost
3019 field on this line */
3020 frow = field_on_page->frow;
3022 /* We walk to the right as long as we are really left of the
3024 while(field_on_page->frow==frow && field_on_page->fcol<fcol)
3025 field_on_page = Sorted_Next_Field(field_on_page);
3027 /* If we wrapped, just go to the left which is the last field on
3029 if (field_on_page->frow!=frow)
3030 field_on_page = Sorted_Previous_Field(field_on_page);
3033 return(field_on_page);
3036 /*----------------------------------------------------------------------------
3037 Inter-Field Navigation routines
3038 --------------------------------------------------------------------------*/
3040 /*---------------------------------------------------------------------------
3041 | Facility : libnform
3042 | Function : static int Inter_Field_Navigation(
3043 | int (* const fct) (FORM *),
3046 | Description : Generic behaviour for changing the current field, the
3047 | field is left and a new field is entered. So the field
3048 | must be validated and the field init/term hooks must
3051 | Return Values : E_OK - success
3052 | E_INVALID_FIELD - field is invalid
3053 | some other - error from subordinate call
3054 +--------------------------------------------------------------------------*/
3055 static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
3059 if (!_nc_Internal_Validation(form))
3060 res = E_INVALID_FIELD;
3063 Call_Hook(form,fieldterm);
3065 Call_Hook(form,fieldinit);
3070 /*---------------------------------------------------------------------------
3071 | Facility : libnform
3072 | Function : static int FN_Next_Field(FORM * form)
3074 | Description : Move to the next field on the current page of the form
3076 | Return Values : E_OK - success
3077 | != E_OK - error from subordinate call
3078 +--------------------------------------------------------------------------*/
3079 static int FN_Next_Field(FORM * form)
3081 return _nc_Set_Current_Field(form,
3082 Next_Field_On_Page(form->current));
3085 /*---------------------------------------------------------------------------
3086 | Facility : libnform
3087 | Function : static int FN_Previous_Field(FORM * form)
3089 | Description : Move to the previous field on the current page of the
3092 | Return Values : E_OK - success
3093 | != E_OK - error from subordinate call
3094 +--------------------------------------------------------------------------*/
3095 static int FN_Previous_Field(FORM * form)
3097 return _nc_Set_Current_Field(form,
3098 Previous_Field_On_Page(form->current));
3101 /*---------------------------------------------------------------------------
3102 | Facility : libnform
3103 | Function : static int FN_First_Field(FORM * form)
3105 | Description : Move to the first field on the current page of the form
3107 | Return Values : E_OK - success
3108 | != E_OK - error from subordinate call
3109 +--------------------------------------------------------------------------*/
3110 static int FN_First_Field(FORM * form)
3112 return _nc_Set_Current_Field(form,
3113 Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
3116 /*---------------------------------------------------------------------------
3117 | Facility : libnform
3118 | Function : static int FN_Last_Field(FORM * form)
3120 | Description : Move to the last field on the current page of the form
3122 | Return Values : E_OK - success
3123 | != E_OK - error from subordinate call
3124 +--------------------------------------------------------------------------*/
3125 static int FN_Last_Field(FORM * form)
3128 _nc_Set_Current_Field(form,
3129 Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
3132 /*---------------------------------------------------------------------------
3133 | Facility : libnform
3134 | Function : static int FN_Sorted_Next_Field(FORM * form)
3136 | Description : Move to the sorted next field on the current page
3139 | Return Values : E_OK - success
3140 | != E_OK - error from subordinate call
3141 +--------------------------------------------------------------------------*/
3142 static int FN_Sorted_Next_Field(FORM * form)
3144 return _nc_Set_Current_Field(form,
3145 Sorted_Next_Field(form->current));
3148 /*---------------------------------------------------------------------------
3149 | Facility : libnform
3150 | Function : static int FN_Sorted_Previous_Field(FORM * form)
3152 | Description : Move to the sorted previous field on the current page
3155 | Return Values : E_OK - success
3156 | != E_OK - error from subordinate call
3157 +--------------------------------------------------------------------------*/
3158 static int FN_Sorted_Previous_Field(FORM * form)
3160 return _nc_Set_Current_Field(form,
3161 Sorted_Previous_Field(form->current));
3164 /*---------------------------------------------------------------------------
3165 | Facility : libnform
3166 | Function : static int FN_Sorted_First_Field(FORM * form)
3168 | Description : Move to the sorted first field on the current page
3171 | Return Values : E_OK - success
3172 | != E_OK - error from subordinate call
3173 +--------------------------------------------------------------------------*/
3174 static int FN_Sorted_First_Field(FORM * form)
3176 return _nc_Set_Current_Field(form,
3177 Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
3180 /*---------------------------------------------------------------------------
3181 | Facility : libnform
3182 | Function : static int FN_Sorted_Last_Field(FORM * form)
3184 | Description : Move to the sorted last field on the current page
3187 | Return Values : E_OK - success
3188 | != E_OK - error from subordinate call
3189 +--------------------------------------------------------------------------*/
3190 static int FN_Sorted_Last_Field(FORM * form)
3192 return _nc_Set_Current_Field(form,
3193 Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
3196 /*---------------------------------------------------------------------------
3197 | Facility : libnform
3198 | Function : static int FN_Left_Field(FORM * form)
3200 | Description : Get the field on the left of the current field on the
3201 | same line and the same page. Cycles through the line.
3203 | Return Values : E_OK - success
3204 | != E_OK - error from subordinate call
3205 +--------------------------------------------------------------------------*/
3206 static int FN_Left_Field(FORM * form)
3208 return _nc_Set_Current_Field(form,
3209 Left_Neighbour_Field(form->current));
3212 /*---------------------------------------------------------------------------
3213 | Facility : libnform
3214 | Function : static int FN_Right_Field(FORM * form)
3216 | Description : Get the field on the right of the current field on the
3217 | same line and the same page. Cycles through the line.
3219 | Return Values : E_OK - success
3220 | != E_OK - error from subordinate call
3221 +--------------------------------------------------------------------------*/
3222 static int FN_Right_Field(FORM * form)
3224 return _nc_Set_Current_Field(form,
3225 Right_Neighbour_Field(form->current));
3228 /*---------------------------------------------------------------------------
3229 | Facility : libnform
3230 | Function : static int FN_Up_Field(FORM * form)
3232 | Description : Get the upper neighbour of the current field. This
3233 | cycles through the page. See the comments of the
3234 | Upper_Neighbour_Field function to understand how
3235 | 'upper' is defined.
3237 | Return Values : E_OK - success
3238 | != E_OK - error from subordinate call
3239 +--------------------------------------------------------------------------*/
3240 static int FN_Up_Field(FORM * form)
3242 return _nc_Set_Current_Field(form,
3243 Upper_Neighbour_Field(form->current));
3246 /*---------------------------------------------------------------------------
3247 | Facility : libnform
3248 | Function : static int FN_Down_Field(FORM * form)
3250 | Description : Get the down neighbour of the current field. This
3251 | cycles through the page. See the comments of the
3252 | Down_Neighbour_Field function to understand how
3253 | 'down' is defined.
3255 | Return Values : E_OK - success
3256 | != E_OK - error from subordinate call
3257 +--------------------------------------------------------------------------*/
3258 static int FN_Down_Field(FORM * form)
3260 return _nc_Set_Current_Field(form,
3261 Down_Neighbour_Field(form->current));
3263 /*----------------------------------------------------------------------------
3264 END of Field Navigation routines
3265 --------------------------------------------------------------------------*/
3267 /*----------------------------------------------------------------------------
3268 Helper routines for Page Navigation
3269 --------------------------------------------------------------------------*/
3271 /*---------------------------------------------------------------------------
3272 | Facility : libnform
3273 | Function : int _nc_Set_Form_Page(FORM * form,
3277 | Description : Make the given page nr. the current page and make
3278 | the given field the current field on the page. If
3279 | for the field NULL is given, make the first field on
3280 | the page the current field. The routine acts only
3281 | if the requested page is not the current page.
3283 | Return Values : E_OK - success
3284 | != E_OK - error from subordinate call
3285 +--------------------------------------------------------------------------*/
3287 _nc_Set_Form_Page(FORM * form, int page, FIELD * field)
3291 if ((form->curpage!=page))
3293 FIELD *last_field, *field_on_page;
3295 werase(Get_Form_Window(form));
3296 form->curpage = page;
3297 last_field = field_on_page = form->field[form->page[page].smin];
3300 if (field_on_page->opts & O_VISIBLE)
3301 if ((res=Display_Field(field_on_page))!=E_OK)
3303 field_on_page = field_on_page->snext;
3304 } while(field_on_page != last_field);
3307 res = _nc_Set_Current_Field(form,field);
3309 /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
3310 because this is already executed in a page navigation
3311 context that contains field navigation
3313 res = FN_First_Field(form);
3318 /*---------------------------------------------------------------------------
3319 | Facility : libnform
3320 | Function : static int Next_Page_Number(const FORM * form)
3322 | Description : Calculate the page number following the current page
3323 | number. This cycles if the highest page number is
3326 | Return Values : The next page number
3327 +--------------------------------------------------------------------------*/
3328 INLINE static int Next_Page_Number(const FORM * form)
3330 return (form->curpage + 1) % form->maxpage;
3333 /*---------------------------------------------------------------------------
3334 | Facility : libnform
3335 | Function : static int Previous_Page_Number(const FORM * form)
3337 | Description : Calculate the page number before the current page
3338 | number. This cycles if the first page number is
3341 | Return Values : The previous page number
3342 +--------------------------------------------------------------------------*/
3343 INLINE static int Previous_Page_Number(const FORM * form)
3345 return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
3348 /*----------------------------------------------------------------------------
3349 Page Navigation routines
3350 --------------------------------------------------------------------------*/
3352 /*---------------------------------------------------------------------------
3353 | Facility : libnform
3354 | Function : static int Page_Navigation(
3355 | int (* const fct) (FORM *),
3358 | Description : Generic behaviour for changing a page. This means
3359 | that the field is left and a new field is entered.
3360 | So the field must be validated and the field init/term
3361 | hooks must be called. Because also the page is changed,
3362 | the forms init/term hooks must be called also.
3364 | Return Values : E_OK - success
3365 | E_INVALID_FIELD - field is invalid
3366 | some other - error from subordinate call
3367 +--------------------------------------------------------------------------*/
3368 static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
3372 if (!_nc_Internal_Validation(form))
3373 res = E_INVALID_FIELD;
3376 Call_Hook(form,fieldterm);
3377 Call_Hook(form,formterm);
3379 Call_Hook(form,forminit);
3380 Call_Hook(form,fieldinit);
3385 /*---------------------------------------------------------------------------
3386 | Facility : libnform
3387 | Function : static int PN_Next_Page(FORM * form)
3389 | Description : Move to the next page of the form
3391 | Return Values : E_OK - success
3392 | != E_OK - error from subordinate call
3393 +--------------------------------------------------------------------------*/
3394 static int PN_Next_Page(FORM * form)
3396 return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
3399 /*---------------------------------------------------------------------------
3400 | Facility : libnform
3401 | Function : static int PN_Previous_Page(FORM * form)
3403 | Description : Move to the previous page of the form
3405 | Return Values : E_OK - success
3406 | != E_OK - error from subordinate call
3407 +--------------------------------------------------------------------------*/
3408 static int PN_Previous_Page(FORM * form)
3410 return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
3413 /*---------------------------------------------------------------------------
3414 | Facility : libnform
3415 | Function : static int PN_First_Page(FORM * form)
3417 | Description : Move to the first page of the form
3419 | Return Values : E_OK - success
3420 | != E_OK - error from subordinate call
3421 +--------------------------------------------------------------------------*/
3422 static int PN_First_Page(FORM * form)
3424 return _nc_Set_Form_Page(form,0,(FIELD *)0);
3427 /*---------------------------------------------------------------------------
3428 | Facility : libnform
3429 | Function : static int PN_Last_Page(FORM * form)
3431 | Description : Move to the last page of the form
3433 | Return Values : E_OK - success
3434 | != E_OK - error from subordinate call
3435 +--------------------------------------------------------------------------*/
3436 static int PN_Last_Page(FORM * form)
3438 return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
3440 /*----------------------------------------------------------------------------
3441 END of Field Navigation routines
3442 --------------------------------------------------------------------------*/
3444 /*----------------------------------------------------------------------------
3445 Helper routines for the core form driver.
3446 --------------------------------------------------------------------------*/
3448 /*---------------------------------------------------------------------------
3449 | Facility : libnform
3450 | Function : static int Data_Entry(FORM * form,int c)
3452 | Description : Enter character c into at the current position of the
3453 | current field of the form.
3455 | Return Values : E_OK -
3456 | E_REQUEST_DENIED -
3458 +--------------------------------------------------------------------------*/
3459 static int Data_Entry(FORM * form, int c)
3461 FIELD *field = form->current;
3462 int result = E_REQUEST_DENIED;
3464 if ( (field->opts & O_EDIT)
3465 #if FIX_FORM_INACTIVE_BUG
3466 && (field->opts & O_ACTIVE)
3470 if ( (field->opts & O_BLANK) &&
3471 First_Position_In_Current_Field(form) &&
3472 !(form->status & _FCHECK_REQUIRED) &&
3473 !(form->status & _WINDOW_MODIFIED) )
3476 if (form->status & _OVLMODE)
3478 waddch(form->w,(chtype)c);
3480 else /* no _OVLMODE */
3482 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
3484 if (!(There_Is_Room ||
3485 ((Single_Line_Field(field) && Growable(field)))))
3486 return E_REQUEST_DENIED;
3488 if (!There_Is_Room && !Field_Grown(field,1))
3489 return E_SYSTEM_ERROR;
3491 winsch(form->w,(chtype)c);
3494 if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
3496 bool End_Of_Field= (((field->drows-1)==form->currow) &&
3497 ((field->dcols-1)==form->curcol));
3498 form->status |= _WINDOW_MODIFIED;
3499 if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3500 result = Inter_Field_Navigation(FN_Next_Field,form);
3503 if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
3504 result = E_SYSTEM_ERROR;
3507 IFN_Next_Character(form);
3516 /* Structure to describe the binding of a request code to a function.
3517 The member keycode codes the request value as well as the generic
3518 routine to use for the request. The code for the generic routine
3519 is coded in the upper 16 Bits while the request code is coded in
3522 In terms of C++ you might think of a request as a class with a
3523 virtual method "perform". The different types of request are
3524 derived from this base class and overload (or not) the base class
3525 implementation of perform.
3528 int keycode; /* must be at least 32 bit: hi:mode, lo: key */
3529 int (*cmd)(FORM *); /* low level driver routine for this key */
3532 /* You may see this is the class-id of the request type class */
3533 #define ID_PN (0x00000000) /* Page navigation */
3534 #define ID_FN (0x00010000) /* Inter-Field navigation */
3535 #define ID_IFN (0x00020000) /* Intra-Field navigation */
3536 #define ID_VSC (0x00030000) /* Vertical Scrolling */
3537 #define ID_HSC (0x00040000) /* Horizontal Scrolling */
3538 #define ID_FE (0x00050000) /* Field Editing */
3539 #define ID_EM (0x00060000) /* Edit Mode */
3540 #define ID_FV (0x00070000) /* Field Validation */
3541 #define ID_CH (0x00080000) /* Choice */
3542 #define ID_Mask (0xffff0000)
3543 #define Key_Mask (0x0000ffff)
3544 #define ID_Shft (16)
3546 /* This array holds all the Binding Infos */
3547 static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
3549 { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
3550 { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
3551 { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
3552 { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
3554 { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
3555 { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
3556 { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
3557 { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
3558 { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
3559 { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
3560 { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
3561 { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
3562 { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
3563 { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
3564 { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
3565 { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
3567 { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
3568 { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
3569 { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
3570 { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
3571 { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
3572 { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
3573 { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
3574 { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
3575 { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
3576 { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
3577 { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
3578 { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
3579 { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
3580 { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
3582 { REQ_NEW_LINE |ID_FE ,FE_New_Line},
3583 { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
3584 { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
3585 { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
3586 { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
3587 { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
3588 { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
3589 { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
3590 { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
3591 { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
3593 { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
3594 { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
3596 { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
3597 { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
3598 { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
3599 { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
3600 { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
3601 { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
3603 { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
3604 { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
3605 { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
3606 { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
3607 { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
3608 { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
3610 { REQ_VALIDATION |ID_FV ,FV_Validation},
3612 { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
3613 { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
3616 /*---------------------------------------------------------------------------
3617 | Facility : libnform
3618 | Function : int form_driver(FORM * form,int c)
3620 | Description : This is the workhorse of the forms system. It checks
3621 | to determine whether the character c is a request or
3622 | data. If it is a request, the form driver executes
3623 | the request and returns the result. If it is data
3624 | (printable character), it enters the data into the
3625 | current position in the current field. If it is not
3626 | recognized, the form driver assumes it is an application
3627 | defined command and returns E_UNKNOWN_COMMAND.
3628 | Application defined command should be defined relative
3629 | to MAX_FORM_COMMAND, the maximum value of a request.
3631 | Return Values : E_OK - success
3632 | E_SYSTEM_ERROR - system error
3633 | E_BAD_ARGUMENT - an argument is incorrect