1 /****************************************************************************
2 * Copyright (c) 1998,2000 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.38 2001/03/25 02:07:50 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);
521 form->w = new_window;
522 Set_Field_Window_Attributes(field,form->w);
524 Buffer_To_Window(field,form->w);
526 wmove(form->w,form->currow,form->curcol);
530 /* reflect changes in linked fields */
531 if (field != field->link)
534 for(linked_field = field->link;
535 linked_field!= field;
536 linked_field = linked_field->link)
538 linked_field->buf = field->buf;
539 linked_field->drows = field->drows;
540 linked_field->dcols = field->dcols;
549 /*---------------------------------------------------------------------------
550 | Facility : libnform
551 | Function : int _nc_Position_Form_Cursor(FORM * form)
553 | Description : Position the cursor in the window for the current
554 | field to be in sync. with the currow and curcol
557 | Return Values : E_OK - success
558 | E_BAD_ARGUMENT - invalid form pointer
559 | E_SYSTEM_ERROR - form has no current field or
561 +--------------------------------------------------------------------------*/
563 _nc_Position_Form_Cursor (FORM * form)
569 return(E_BAD_ARGUMENT);
571 if (!form->w || !form->current)
572 return(E_SYSTEM_ERROR);
574 field = form->current;
575 formwin = Get_Form_Window(form);
577 wmove( form->w, form->currow, form->curcol );
578 if ( Has_Invisible_Parts(field) )
580 /* in this case fieldwin isn't derived from formwin, so we have
581 to move the cursor in formwin by hand... */
583 field->frow + form->currow - form->toprow,
584 field->fcol + form->curcol - form->begincol);
592 /*---------------------------------------------------------------------------
593 | Facility : libnform
594 | Function : int _nc_Refresh_Current_Field(FORM * form)
596 | Description : Propagate the changes in the fields window to the
597 | window of the form.
599 | Return Values : E_OK - on success
600 | E_BAD_ARGUMENT - invalid form pointer
601 | E_SYSTEM_ERROR - general error
602 +--------------------------------------------------------------------------*/
604 _nc_Refresh_Current_Field (FORM * form)
610 RETURN(E_BAD_ARGUMENT);
612 if (!form->w || !form->current)
613 RETURN(E_SYSTEM_ERROR);
615 field = form->current;
616 formwin = Get_Form_Window(form);
618 if (field->opts & O_PUBLIC)
620 if (Is_Scroll_Field(field))
622 /* Again, in this case the fieldwin isn't derived from formwin,
623 so we have to perform a copy operation. */
624 if (Single_Line_Field(field))
625 { /* horizontal scrolling */
626 if (form->curcol < form->begincol)
627 form->begincol = form->curcol;
630 if (form->curcol >= (form->begincol + field->cols))
631 form->begincol = form->curcol - field->cols + 1;
640 field->cols + field->fcol - 1,
644 { /* A multiline, i.e. vertical scrolling field */
645 int row_after_bottom,first_modified_row,first_unmodified_row;
647 if (field->drows > field->rows)
649 row_after_bottom = form->toprow + field->rows;
650 if (form->currow < form->toprow)
652 form->toprow = form->currow;
653 field->status |= _NEWTOP;
655 if (form->currow >= row_after_bottom)
657 form->toprow = form->currow - field->rows + 1;
658 field->status |= _NEWTOP;
660 if (field->status & _NEWTOP)
661 { /* means we have to copy whole range */
662 first_modified_row = form->toprow;
663 first_unmodified_row = first_modified_row + field->rows;
664 field->status &= ~_NEWTOP;
667 { /* we try to optimize : finding the range of touched
669 first_modified_row = form->toprow;
670 while(first_modified_row < row_after_bottom)
672 if (is_linetouched(form->w,first_modified_row))
674 first_modified_row++;
676 first_unmodified_row = first_modified_row;
677 while(first_unmodified_row < row_after_bottom)
679 if (!is_linetouched(form->w,first_unmodified_row))
681 first_unmodified_row++;
687 first_modified_row = form->toprow;
688 first_unmodified_row = first_modified_row + field->rows;
690 if (first_unmodified_row != first_modified_row)
695 field->frow + first_modified_row - form->toprow,
697 field->frow + first_unmodified_row - form->toprow - 1,
698 field->cols + field->fcol - 1,
704 { /* if the field-window is simply a derived window, i.e. contains
705 no invisible parts, the whole thing is trivial
711 return _nc_Position_Form_Cursor(form);
714 /*---------------------------------------------------------------------------
715 | Facility : libnform
716 | Function : static void Perform_Justification(
720 | Description : Output field with requested justification
723 +--------------------------------------------------------------------------*/
724 static void Perform_Justification(FIELD * field, WINDOW * win)
730 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
731 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
735 assert(win && (field->drows == 1) && (field->dcols == field->cols));
742 col = (field->cols - len)/2;
745 col = field->cols - len;
752 waddnstr(win,bp,len);
756 /*---------------------------------------------------------------------------
757 | Facility : libnform
758 | Function : static void Undo_Justification(
762 | Description : Display field without any justification, i.e.
766 +--------------------------------------------------------------------------*/
767 static void Undo_Justification(FIELD * field, WINDOW * win)
772 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
773 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
779 waddnstr(win,bp,len);
783 /*---------------------------------------------------------------------------
784 | Facility : libnform
785 | Function : static bool Check_Char(
788 | TypeArgument *argp)
790 | Description : Perform a single character check for character ch
791 | according to the fieldtype instance.
793 | Return Values : TRUE - Character is valid
794 | FALSE - Character is invalid
795 +--------------------------------------------------------------------------*/
796 static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
800 if (typ->status & _LINKED_TYPE)
804 Check_Char(typ->left ,ch,argp->left ) ||
805 Check_Char(typ->right,ch,argp->right) );
810 return typ->ccheck(ch,(void *)argp);
813 return (isprint((unsigned char)ch) ? TRUE : FALSE);
816 /*---------------------------------------------------------------------------
817 | Facility : libnform
818 | Function : static int Display_Or_Erase_Field(
822 | Description : Create a subwindow for the field and display the
823 | buffer contents (apply justification if required)
824 | or simply erase the field.
826 | Return Values : E_OK - on success
827 | E_SYSTEM_ERROR - some error (typical no memory)
828 +--------------------------------------------------------------------------*/
829 static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
835 return E_SYSTEM_ERROR;
837 fwin = Get_Form_Window(field->form);
839 field->rows,field->cols,field->frow,field->fcol);
842 return E_SYSTEM_ERROR;
845 if (field->opts & O_VISIBLE)
846 Set_Field_Window_Attributes(field,win);
848 wattrset(win,getattrs(fwin));
854 if (field->opts & O_PUBLIC)
856 if (Justification_Allowed(field))
857 Perform_Justification(field,win);
859 Buffer_To_Window(field,win);
861 field->status &= ~_NEWTOP;
868 /* Macros to preset the bEraseFlag */
869 #define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
870 #define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
872 /*---------------------------------------------------------------------------
873 | Facility : libnform
874 | Function : static int Synchronize_Field(FIELD * field)
876 | Description : Synchronize the windows content with the value in
879 | Return Values : E_OK - success
880 | E_BAD_ARGUMENT - invalid field pointer
881 | E_SYSTEM_ERROR - some severe basic error
882 +--------------------------------------------------------------------------*/
883 static int Synchronize_Field(FIELD * field)
889 return(E_BAD_ARGUMENT);
891 if (((form=field->form) != (FORM *)0)
892 && Field_Really_Appears(field))
894 if (field == form->current)
896 form->currow = form->curcol = form->toprow = form->begincol = 0;
899 if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
900 Undo_Justification( field, form->w );
902 Buffer_To_Window( field, form->w );
904 field->status |= _NEWTOP;
905 res = _nc_Refresh_Current_Field( form );
908 res = Display_Field( field );
910 field->status |= _CHANGED;
914 /*---------------------------------------------------------------------------
915 | Facility : libnform
916 | Function : static int Synchronize_Linked_Fields(FIELD * field)
918 | Description : Propagate the Synchronize_Field function to all linked
919 | fields. The first error that occurs in the sequence
920 | of updates is the returnvalue.
922 | Return Values : E_OK - success
923 | E_BAD_ARGUMENT - invalid field pointer
924 | E_SYSTEM_ERROR - some severe basic error
925 +--------------------------------------------------------------------------*/
926 static int Synchronize_Linked_Fields(FIELD * field)
933 return(E_BAD_ARGUMENT);
936 return(E_SYSTEM_ERROR);
938 for(linked_field = field->link;
939 linked_field!= field;
940 linked_field = linked_field->link )
942 if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
949 /*---------------------------------------------------------------------------
950 | Facility : libnform
951 | Function : int _nc_Synchronize_Attributes(FIELD * field)
953 | Description : If a fields visual attributes have changed, this
954 | routine is called to propagate those changes to the
957 | Return Values : E_OK - success
958 | E_BAD_ARGUMENT - invalid field pointer
959 | E_SYSTEM_ERROR - some severe basic error
960 +--------------------------------------------------------------------------*/
962 _nc_Synchronize_Attributes (FIELD * field)
969 return(E_BAD_ARGUMENT);
971 if (((form=field->form) != (FORM *)0)
972 && Field_Really_Appears(field))
974 if (form->current==field)
976 Synchronize_Buffer(form);
977 Set_Field_Window_Attributes(field,form->w);
979 if (field->opts & O_PUBLIC)
981 if (Justification_Allowed(field))
982 Undo_Justification(field,form->w);
984 Buffer_To_Window(field,form->w);
988 formwin = Get_Form_Window(form);
989 copywin(form->w,formwin,
991 field->frow,field->fcol,
992 field->rows-1,field->cols-1,0);
994 Buffer_To_Window(field,form->w);
995 field->status |= _NEWTOP; /* fake refresh to paint all */
996 _nc_Refresh_Current_Field(form);
1001 res = Display_Field(field);
1007 /*---------------------------------------------------------------------------
1008 | Facility : libnform
1009 | Function : int _nc_Synchronize_Options(FIELD * field,
1010 | Field_Options newopts)
1012 | Description : If a fields options have changed, this routine is
1013 | called to propagate these changes to the screen and
1014 | to really change the behaviour of the field.
1016 | Return Values : E_OK - success
1017 | E_BAD_ARGUMENT - invalid field pointer
1018 | E_SYSTEM_ERROR - some severe basic error
1019 +--------------------------------------------------------------------------*/
1021 _nc_Synchronize_Options
1022 (FIELD *field, Field_Options newopts)
1024 Field_Options oldopts;
1025 Field_Options changed_opts;
1030 return(E_BAD_ARGUMENT);
1032 oldopts = field->opts;
1033 changed_opts = oldopts ^ newopts;
1034 field->opts = newopts;
1039 if (form->current == field)
1041 field->opts = oldopts;
1045 if (form->status & _POSTED)
1047 if ((form->curpage == field->page))
1049 if (changed_opts & O_VISIBLE)
1051 if (newopts & O_VISIBLE)
1052 res = Display_Field(field);
1054 res = Erase_Field(field);
1058 if ((changed_opts & O_PUBLIC) &&
1059 (newopts & O_VISIBLE))
1060 res = Display_Field(field);
1066 if (changed_opts & O_STATIC)
1068 bool single_line_field = Single_Line_Field(field);
1071 if (newopts & O_STATIC)
1072 { /* the field becomes now static */
1073 field->status &= ~_MAY_GROW;
1074 /* if actually we have no hidden columns, justification may
1076 if (single_line_field &&
1077 (field->cols == field->dcols) &&
1078 (field->just != NO_JUSTIFICATION) &&
1079 Field_Really_Appears(field))
1081 res2 = Display_Field(field);
1085 { /* field is no longer static */
1086 if ((field->maxgrow==0) ||
1087 ( single_line_field && (field->dcols < field->maxgrow)) ||
1088 (!single_line_field && (field->drows < field->maxgrow)))
1090 field->status |= _MAY_GROW;
1091 /* a field with justification now changes its behaviour,
1092 so we must redisplay it */
1093 if (single_line_field &&
1094 (field->just != NO_JUSTIFICATION) &&
1095 Field_Really_Appears(field))
1097 res2 = Display_Field(field);
1108 /*---------------------------------------------------------------------------
1109 | Facility : libnform
1110 | Function : int _nc_Set_Current_Field(FORM * form,
1113 | Description : Make the newfield the new current field.
1115 | Return Values : E_OK - success
1116 | E_BAD_ARGUMENT - invalid form or field pointer
1117 | E_SYSTEM_ERROR - some severe basic error
1118 +--------------------------------------------------------------------------*/
1120 _nc_Set_Current_Field
1121 (FORM *form, FIELD *newfield)
1126 if (!form || !newfield || !form->current || (newfield->form!=form))
1127 return(E_BAD_ARGUMENT);
1129 if ( (form->status & _IN_DRIVER) )
1130 return(E_BAD_STATE);
1133 return(E_NOT_CONNECTED);
1135 field = form->current;
1137 if ((field!=newfield) ||
1138 !(form->status & _POSTED))
1141 (field->opts & O_VISIBLE) &&
1142 (field->form->curpage == field->page))
1144 _nc_Refresh_Current_Field(form);
1145 if (field->opts & O_PUBLIC)
1147 if (field->drows > field->rows)
1149 if (form->toprow==0)
1150 field->status &= ~_NEWTOP;
1152 field->status |= _NEWTOP;
1156 if (Justification_Allowed(field))
1158 Window_To_Buffer(form->w,field);
1160 Perform_Justification(field,form->w);
1166 form->w = (WINDOW *)0;
1171 if (Has_Invisible_Parts(field))
1172 new_window = newpad(field->drows,field->dcols);
1174 new_window = derwin(Get_Form_Window(form),
1175 field->rows,field->cols,field->frow,field->fcol);
1178 return(E_SYSTEM_ERROR);
1180 form->current = field;
1184 form->w = new_window;
1186 form->status &= ~_WINDOW_MODIFIED;
1187 Set_Field_Window_Attributes(field,form->w);
1189 if (Has_Invisible_Parts(field))
1192 Buffer_To_Window(field,form->w);
1196 if (Justification_Allowed(field))
1199 Undo_Justification(field,form->w);
1204 untouchwin(form->w);
1207 form->currow = form->curcol = form->toprow = form->begincol = 0;
1211 /*----------------------------------------------------------------------------
1212 Intra-Field Navigation routines
1213 --------------------------------------------------------------------------*/
1215 /*---------------------------------------------------------------------------
1216 | Facility : libnform
1217 | Function : static int IFN_Next_Character(FORM * form)
1219 | Description : Move to the next character in the field. In a multiline
1220 | field this wraps at the end of the line.
1222 | Return Values : E_OK - success
1223 | E_REQUEST_DENIED - at the rightmost position
1224 +--------------------------------------------------------------------------*/
1225 static int IFN_Next_Character(FORM * form)
1227 FIELD *field = form->current;
1229 if ((++(form->curcol))==field->dcols)
1231 if ((++(form->currow))==field->drows)
1233 #if GROW_IF_NAVIGATE
1234 if (!Single_Line_Field(field) && Field_Grown(field,1)) {
1240 #if GROW_IF_NAVIGATE
1241 if (Single_Line_Field(field) && Field_Grown(field,1))
1245 return(E_REQUEST_DENIED);
1252 /*---------------------------------------------------------------------------
1253 | Facility : libnform
1254 | Function : static int IFN_Previous_Character(FORM * form)
1256 | Description : Move to the previous character in the field. In a
1257 | multiline field this wraps and the beginning of the
1260 | Return Values : E_OK - success
1261 | E_REQUEST_DENIED - at the leftmost position
1262 +--------------------------------------------------------------------------*/
1263 static int IFN_Previous_Character(FORM * form)
1265 if ((--(form->curcol))<0)
1267 if ((--(form->currow))<0)
1271 return(E_REQUEST_DENIED);
1273 form->curcol = form->current->dcols - 1;
1278 /*---------------------------------------------------------------------------
1279 | Facility : libnform
1280 | Function : static int IFN_Next_Line(FORM * form)
1282 | Description : Move to the beginning of the next line in the field
1284 | Return Values : E_OK - success
1285 | E_REQUEST_DENIED - at the last line
1286 +--------------------------------------------------------------------------*/
1287 static int IFN_Next_Line(FORM * form)
1289 FIELD *field = form->current;
1291 if ((++(form->currow))==field->drows)
1293 #if GROW_IF_NAVIGATE
1294 if (!Single_Line_Field(field) && Field_Grown(field,1))
1298 return(E_REQUEST_DENIED);
1304 /*---------------------------------------------------------------------------
1305 | Facility : libnform
1306 | Function : static int IFN_Previous_Line(FORM * form)
1308 | Description : Move to the beginning of the previous line in the field
1310 | Return Values : E_OK - success
1311 | E_REQUEST_DENIED - at the first line
1312 +--------------------------------------------------------------------------*/
1313 static int IFN_Previous_Line(FORM * form)
1315 if ( (--(form->currow)) < 0 )
1318 return(E_REQUEST_DENIED);
1324 /*---------------------------------------------------------------------------
1325 | Facility : libnform
1326 | Function : static int IFN_Next_Word(FORM * form)
1328 | Description : Move to the beginning of the next word in the field.
1330 | Return Values : E_OK - success
1331 | E_REQUEST_DENIED - there is no next word
1332 +--------------------------------------------------------------------------*/
1333 static int IFN_Next_Word(FORM * form)
1335 FIELD *field = form->current;
1336 char *bp = Address_Of_Current_Position_In_Buffer(form);
1340 /* We really need access to the data, so we have to synchronize */
1341 Synchronize_Buffer(form);
1343 /* Go to the first whitespace after the current position (including
1344 current position). This is then the startpoint to look for the
1345 next non-blank data */
1346 s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
1347 (int)(bp - field->buf));
1349 /* Find the start of the next word */
1350 t = Get_Start_Of_Data(s,Buffer_Length(field) -
1351 (int)(s - field->buf));
1352 #if !FRIENDLY_PREV_NEXT_WORD
1354 return(E_REQUEST_DENIED);
1358 Adjust_Cursor_Position(form,t);
1363 /*---------------------------------------------------------------------------
1364 | Facility : libnform
1365 | Function : static int IFN_Previous_Word(FORM * form)
1367 | Description : Move to the beginning of the previous word in the field.
1369 | Return Values : E_OK - success
1370 | E_REQUEST_DENIED - there is no previous word
1371 +--------------------------------------------------------------------------*/
1372 static int IFN_Previous_Word(FORM * form)
1374 FIELD *field = form->current;
1375 char *bp = Address_Of_Current_Position_In_Buffer(form);
1380 /* We really need access to the data, so we have to synchronize */
1381 Synchronize_Buffer(form);
1383 s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
1384 /* s points now right after the last non-blank in the buffer before bp.
1385 If bp was in a word, s equals bp. In this case we must find the last
1386 whitespace in the buffer before bp and repeat the game to really find
1387 the previous word! */
1391 /* And next call now goes backward to look for the last whitespace
1392 before that, pointing right after this, so it points to the begin
1393 of the previous word.
1395 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1396 #if !FRIENDLY_PREV_NEXT_WORD
1398 return(E_REQUEST_DENIED);
1401 { /* and do it again, replacing bp by t */
1402 s = After_End_Of_Data(field->buf,(int)(t - field->buf));
1403 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1404 #if !FRIENDLY_PREV_NEXT_WORD
1406 return(E_REQUEST_DENIED);
1409 Adjust_Cursor_Position(form,t);
1413 /*---------------------------------------------------------------------------
1414 | Facility : libnform
1415 | Function : static int IFN_Beginning_Of_Field(FORM * form)
1417 | Description : Place the cursor at the first non-pad character in
1420 | Return Values : E_OK - success
1421 +--------------------------------------------------------------------------*/
1422 static int IFN_Beginning_Of_Field(FORM * form)
1424 FIELD *field = form->current;
1426 Synchronize_Buffer(form);
1427 Adjust_Cursor_Position(form,
1428 Get_Start_Of_Data(field->buf,Buffer_Length(field)));
1432 /*---------------------------------------------------------------------------
1433 | Facility : libnform
1434 | Function : static int IFN_End_Of_Field(FORM * form)
1436 | Description : Place the cursor after the last non-pad character in
1437 | the field. If the field occupies the last position in
1438 | the buffer, the cursos is positioned on the last
1441 | Return Values : E_OK - success
1442 +--------------------------------------------------------------------------*/
1443 static int IFN_End_Of_Field(FORM * form)
1445 FIELD *field = form->current;
1448 Synchronize_Buffer(form);
1449 pos = After_End_Of_Data(field->buf,Buffer_Length(field));
1450 if (pos==(field->buf + Buffer_Length(field)))
1452 Adjust_Cursor_Position(form,pos);
1456 /*---------------------------------------------------------------------------
1457 | Facility : libnform
1458 | Function : static int IFN_Beginning_Of_Line(FORM * form)
1460 | Description : Place the cursor on the first non-pad character in
1461 | the current line of the field.
1463 | Return Values : E_OK - success
1464 +--------------------------------------------------------------------------*/
1465 static int IFN_Beginning_Of_Line(FORM * form)
1467 FIELD *field = form->current;
1469 Synchronize_Buffer(form);
1470 Adjust_Cursor_Position(form,
1471 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1476 /*---------------------------------------------------------------------------
1477 | Facility : libnform
1478 | Function : static int IFN_End_Of_Line(FORM * form)
1480 | Description : Place the cursor after the last non-pad character in the
1481 | current line of the field. If the field occupies the
1482 | last column in the line, the cursor is positioned on the
1483 | last character of the line.
1485 | Return Values : E_OK - success
1486 +--------------------------------------------------------------------------*/
1487 static int IFN_End_Of_Line(FORM * form)
1489 FIELD *field = form->current;
1493 Synchronize_Buffer(form);
1494 bp = Address_Of_Current_Row_In_Buffer(form);
1495 pos = After_End_Of_Data(bp,field->dcols);
1496 if (pos == (bp + field->dcols))
1498 Adjust_Cursor_Position(form,pos);
1502 /*---------------------------------------------------------------------------
1503 | Facility : libnform
1504 | Function : static int IFN_Left_Character(FORM * form)
1506 | Description : Move one character to the left in the current line.
1507 | This doesn't cycle.
1509 | Return Values : E_OK - success
1510 | E_REQUEST_DENIED - already in first column
1511 +--------------------------------------------------------------------------*/
1512 static int IFN_Left_Character(FORM * form)
1514 if ( (--(form->curcol)) < 0 )
1517 return(E_REQUEST_DENIED);
1522 /*---------------------------------------------------------------------------
1523 | Facility : libnform
1524 | Function : static int IFN_Right_Character(FORM * form)
1526 | Description : Move one character to the right in the current line.
1527 | This doesn't cycle.
1529 | Return Values : E_OK - success
1530 | E_REQUEST_DENIED - already in last column
1531 +--------------------------------------------------------------------------*/
1532 static int IFN_Right_Character(FORM * form)
1534 if ( (++(form->curcol)) == form->current->dcols )
1536 #if GROW_IF_NAVIGATE
1537 FIELD *field = form->current;
1538 if (Single_Line_Field(field) && Field_Grown(field,1))
1542 return(E_REQUEST_DENIED);
1547 /*---------------------------------------------------------------------------
1548 | Facility : libnform
1549 | Function : static int IFN_Up_Character(FORM * form)
1551 | Description : Move one line up. This doesn't cycle through the lines
1554 | Return Values : E_OK - success
1555 | E_REQUEST_DENIED - already in last column
1556 +--------------------------------------------------------------------------*/
1557 static int IFN_Up_Character(FORM * form)
1559 if ( (--(form->currow)) < 0 )
1562 return(E_REQUEST_DENIED);
1567 /*---------------------------------------------------------------------------
1568 | Facility : libnform
1569 | Function : static int IFN_Down_Character(FORM * form)
1571 | Description : Move one line down. This doesn't cycle through the
1572 | lines of the field.
1574 | Return Values : E_OK - success
1575 | E_REQUEST_DENIED - already in last column
1576 +--------------------------------------------------------------------------*/
1577 static int IFN_Down_Character(FORM * form)
1579 FIELD *field = form->current;
1581 if ( (++(form->currow)) == field->drows )
1583 #if GROW_IF_NAVIGATE
1584 if (!Single_Line_Field(field) && Field_Grown(field,1))
1588 return(E_REQUEST_DENIED);
1592 /*----------------------------------------------------------------------------
1593 END of Intra-Field Navigation routines
1594 --------------------------------------------------------------------------*/
1596 /*----------------------------------------------------------------------------
1597 Vertical scrolling helper routines
1598 --------------------------------------------------------------------------*/
1600 /*---------------------------------------------------------------------------
1601 | Facility : libnform
1602 | Function : static int VSC_Generic(FORM *form, int lines)
1604 | Description : Scroll multi-line field forward (lines>0) or
1605 | backward (lines<0) this many lines.
1607 | Return Values : E_OK - success
1608 | E_REQUEST_DENIED - can't scroll
1609 +--------------------------------------------------------------------------*/
1610 static int VSC_Generic(FORM *form, int lines)
1612 FIELD *field = form->current;
1613 int res = E_REQUEST_DENIED;
1614 int rows_to_go = (lines > 0 ? lines : -lines);
1618 if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
1619 rows_to_go = (field->drows - field->rows - form->toprow);
1623 form->currow += rows_to_go;
1624 form->toprow += rows_to_go;
1630 if (rows_to_go > form->toprow)
1631 rows_to_go = form->toprow;
1635 form->currow -= rows_to_go;
1636 form->toprow -= rows_to_go;
1642 /*----------------------------------------------------------------------------
1643 End of Vertical scrolling helper routines
1644 --------------------------------------------------------------------------*/
1646 /*----------------------------------------------------------------------------
1647 Vertical scrolling routines
1648 --------------------------------------------------------------------------*/
1650 /*---------------------------------------------------------------------------
1651 | Facility : libnform
1652 | Function : static int Vertical_Scrolling(
1653 | int (* const fct) (FORM *),
1656 | Description : Performs the generic vertical scrolling routines.
1657 | This has to check for a multi-line field and to set
1658 | the _NEWTOP flag if scrolling really occured.
1660 | Return Values : Propagated error code from low-level driver calls
1661 +--------------------------------------------------------------------------*/
1662 static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
1664 int res = E_REQUEST_DENIED;
1666 if (!Single_Line_Field(form->current))
1670 form->current->status |= _NEWTOP;
1675 /*---------------------------------------------------------------------------
1676 | Facility : libnform
1677 | Function : static int VSC_Scroll_Line_Forward(FORM * form)
1679 | Description : Scroll multi-line field forward a line
1681 | Return Values : E_OK - success
1682 | E_REQUEST_DENIED - no data ahead
1683 +--------------------------------------------------------------------------*/
1684 static int VSC_Scroll_Line_Forward(FORM * form)
1686 return VSC_Generic(form,1);
1689 /*---------------------------------------------------------------------------
1690 | Facility : libnform
1691 | Function : static int VSC_Scroll_Line_Backward(FORM * form)
1693 | Description : Scroll multi-line field backward a line
1695 | Return Values : E_OK - success
1696 | E_REQUEST_DENIED - no data behind
1697 +--------------------------------------------------------------------------*/
1698 static int VSC_Scroll_Line_Backward(FORM * form)
1700 return VSC_Generic(form,-1);
1703 /*---------------------------------------------------------------------------
1704 | Facility : libnform
1705 | Function : static int VSC_Scroll_Page_Forward(FORM * form)
1707 | Description : Scroll a multi-line field forward a page
1709 | Return Values : E_OK - success
1710 | E_REQUEST_DENIED - no data ahead
1711 +--------------------------------------------------------------------------*/
1712 static int VSC_Scroll_Page_Forward(FORM * form)
1714 return VSC_Generic(form,form->current->rows);
1717 /*---------------------------------------------------------------------------
1718 | Facility : libnform
1719 | Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1721 | Description : Scroll a multi-line field forward half a page
1723 | Return Values : E_OK - success
1724 | E_REQUEST_DENIED - no data ahead
1725 +--------------------------------------------------------------------------*/
1726 static int VSC_Scroll_Half_Page_Forward(FORM * form)
1728 return VSC_Generic(form,(form->current->rows + 1)/2);
1731 /*---------------------------------------------------------------------------
1732 | Facility : libnform
1733 | Function : static int VSC_Scroll_Page_Backward(FORM * form)
1735 | Description : Scroll a multi-line field backward a page
1737 | Return Values : E_OK - success
1738 | E_REQUEST_DENIED - no data behind
1739 +--------------------------------------------------------------------------*/
1740 static int VSC_Scroll_Page_Backward(FORM * form)
1742 return VSC_Generic(form, -(form->current->rows));
1745 /*---------------------------------------------------------------------------
1746 | Facility : libnform
1747 | Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
1749 | Description : Scroll a multi-line field backward half a page
1751 | Return Values : E_OK - success
1752 | E_REQUEST_DENIED - no data behind
1753 +--------------------------------------------------------------------------*/
1754 static int VSC_Scroll_Half_Page_Backward(FORM * form)
1756 return VSC_Generic(form, -((form->current->rows + 1)/2));
1758 /*----------------------------------------------------------------------------
1759 End of Vertical scrolling routines
1760 --------------------------------------------------------------------------*/
1762 /*----------------------------------------------------------------------------
1763 Horizontal scrolling helper routines
1764 --------------------------------------------------------------------------*/
1766 /*---------------------------------------------------------------------------
1767 | Facility : libnform
1768 | Function : static int HSC_Generic(FORM *form, int columns)
1770 | Description : Scroll single-line field forward (columns>0) or
1771 | backward (columns<0) this many columns.
1773 | Return Values : E_OK - success
1774 | E_REQUEST_DENIED - can't scroll
1775 +--------------------------------------------------------------------------*/
1776 static int HSC_Generic(FORM *form, int columns)
1778 FIELD *field = form->current;
1779 int res = E_REQUEST_DENIED;
1780 int cols_to_go = (columns > 0 ? columns : -columns);
1784 if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
1785 cols_to_go = field->dcols - field->cols - form->begincol;
1789 form->curcol += cols_to_go;
1790 form->begincol += cols_to_go;
1796 if ( cols_to_go > form->begincol )
1797 cols_to_go = form->begincol;
1801 form->curcol -= cols_to_go;
1802 form->begincol -= cols_to_go;
1808 /*----------------------------------------------------------------------------
1809 End of Horizontal scrolling helper routines
1810 --------------------------------------------------------------------------*/
1812 /*----------------------------------------------------------------------------
1813 Horizontal scrolling routines
1814 --------------------------------------------------------------------------*/
1816 /*---------------------------------------------------------------------------
1817 | Facility : libnform
1818 | Function : static int Horizontal_Scrolling(
1819 | int (* const fct) (FORM *),
1822 | Description : Performs the generic horizontal scrolling routines.
1823 | This has to check for a single-line field.
1825 | Return Values : Propagated error code from low-level driver calls
1826 +--------------------------------------------------------------------------*/
1827 static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
1829 if (Single_Line_Field(form->current))
1832 return(E_REQUEST_DENIED);
1835 /*---------------------------------------------------------------------------
1836 | Facility : libnform
1837 | Function : static int HSC_Scroll_Char_Forward(FORM * form)
1839 | Description : Scroll single-line field forward a character
1841 | Return Values : E_OK - success
1842 | E_REQUEST_DENIED - no data ahead
1843 +--------------------------------------------------------------------------*/
1844 static int HSC_Scroll_Char_Forward(FORM *form)
1846 return HSC_Generic(form,1);
1849 /*---------------------------------------------------------------------------
1850 | Facility : libnform
1851 | Function : static int HSC_Scroll_Char_Backward(FORM * form)
1853 | Description : Scroll single-line field backward a character
1855 | Return Values : E_OK - success
1856 | E_REQUEST_DENIED - no data behind
1857 +--------------------------------------------------------------------------*/
1858 static int HSC_Scroll_Char_Backward(FORM *form)
1860 return HSC_Generic(form,-1);
1863 /*---------------------------------------------------------------------------
1864 | Facility : libnform
1865 | Function : static int HSC_Horizontal_Line_Forward(FORM* form)
1867 | Description : Scroll single-line field forward a line
1869 | Return Values : E_OK - success
1870 | E_REQUEST_DENIED - no data ahead
1871 +--------------------------------------------------------------------------*/
1872 static int HSC_Horizontal_Line_Forward(FORM * form)
1874 return HSC_Generic(form,form->current->cols);
1877 /*---------------------------------------------------------------------------
1878 | Facility : libnform
1879 | Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
1881 | Description : Scroll single-line field forward half a line
1883 | Return Values : E_OK - success
1884 | E_REQUEST_DENIED - no data ahead
1885 +--------------------------------------------------------------------------*/
1886 static int HSC_Horizontal_Half_Line_Forward(FORM * form)
1888 return HSC_Generic(form,(form->current->cols + 1)/2);
1891 /*---------------------------------------------------------------------------
1892 | Facility : libnform
1893 | Function : static int HSC_Horizontal_Line_Backward(FORM* form)
1895 | Description : Scroll single-line field backward a line
1897 | Return Values : E_OK - success
1898 | E_REQUEST_DENIED - no data behind
1899 +--------------------------------------------------------------------------*/
1900 static int HSC_Horizontal_Line_Backward(FORM * form)
1902 return HSC_Generic(form,-(form->current->cols));
1905 /*---------------------------------------------------------------------------
1906 | Facility : libnform
1907 | Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
1909 | Description : Scroll single-line field backward half a line
1911 | Return Values : E_OK - success
1912 | E_REQUEST_DENIED - no data behind
1913 +--------------------------------------------------------------------------*/
1914 static int HSC_Horizontal_Half_Line_Backward(FORM * form)
1916 return HSC_Generic(form,-((form->current->cols + 1)/2));
1919 /*----------------------------------------------------------------------------
1920 End of Horizontal scrolling routines
1921 --------------------------------------------------------------------------*/
1923 /*----------------------------------------------------------------------------
1924 Helper routines for Field Editing
1925 --------------------------------------------------------------------------*/
1927 /*---------------------------------------------------------------------------
1928 | Facility : libnform
1929 | Function : static bool Is_There_Room_For_A_Line(FORM * form)
1931 | Description : Check whether or not there is enough room in the
1932 | buffer to enter a whole line.
1934 | Return Values : TRUE - there is enough space
1935 | FALSE - there is not enough space
1936 +--------------------------------------------------------------------------*/
1937 INLINE static bool Is_There_Room_For_A_Line(FORM * form)
1939 FIELD *field = form->current;
1940 char *begin_of_last_line, *s;
1942 Synchronize_Buffer(form);
1943 begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
1944 s = After_End_Of_Data(begin_of_last_line,field->dcols);
1945 return ((s==begin_of_last_line) ? TRUE : FALSE);
1948 /*---------------------------------------------------------------------------
1949 | Facility : libnform
1950 | Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1952 | Description : Checks whether or not there is room for a new character
1953 | in the current line.
1955 | Return Values : TRUE - there is room
1956 | FALSE - there is not enough room (line full)
1957 +--------------------------------------------------------------------------*/
1958 INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1960 int last_char_in_line;
1962 wmove(form->w,form->currow,form->current->dcols-1);
1963 last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
1964 wmove(form->w,form->currow,form->curcol);
1965 return (((last_char_in_line == form->current->pad) ||
1966 is_blank(last_char_in_line)) ? TRUE : FALSE);
1969 #define There_Is_No_Room_For_A_Char_In_Line(f) \
1970 !Is_There_Room_For_A_Char_In_Line(f)
1972 /*---------------------------------------------------------------------------
1973 | Facility : libnform
1974 | Function : static int Insert_String(
1980 | Description : Insert the 'len' characters beginning at pointer 'txt'
1981 | into the 'row' of the 'form'. The insertion occurs
1982 | on the beginning of the row, all other characters are
1983 | moved to the right. After the text a pad character will
1984 | be inserted to separate the text from the rest. If
1985 | necessary the insertion moves characters on the next
1986 | line to make place for the requested insertion string.
1988 | Return Values : E_OK - success
1989 | E_REQUEST_DENIED -
1990 | E_SYSTEM_ERROR - system error
1991 +--------------------------------------------------------------------------*/
1992 static int Insert_String(FORM *form, int row, char *txt, int len)
1994 FIELD *field = form->current;
1995 char *bp = Address_Of_Row_In_Buffer(field,row);
1996 int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
1997 int freelen = field->dcols - datalen;
1998 int requiredlen = len+1;
2000 int result = E_REQUEST_DENIED;
2001 const char *Space = " ";
2003 if (freelen >= requiredlen)
2005 wmove(form->w,row,0);
2006 winsnstr(form->w,txt,len);
2007 wmove(form->w,row,len);
2008 winsnstr(form->w,Space,1);
2012 { /* we have to move characters on the next line. If we are on the
2013 last line this may work, if the field is growable */
2014 if ((row == (field->drows - 1)) && Growable(field))
2016 if (!Field_Grown(field,1))
2017 return(E_SYSTEM_ERROR);
2018 /* !!!Side-Effect : might be changed due to growth!!! */
2019 bp = Address_Of_Row_In_Buffer(field,row);
2022 if (row < (field->drows - 1))
2024 split = After_Last_Whitespace_Character(bp,
2025 (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
2026 requiredlen) - bp));
2027 /* split points now to the first character of the portion of the
2028 line that must be moved to the next line */
2029 datalen = (int)(split-bp); /* + freelen has to stay on this line */
2030 freelen = field->dcols - (datalen + freelen); /* for the next line */
2032 if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
2034 wmove(form->w,row,datalen);
2036 wmove(form->w,row,0);
2037 winsnstr(form->w,txt,len);
2038 wmove(form->w,row,len);
2039 winsnstr(form->w,Space,1);
2047 /*---------------------------------------------------------------------------
2048 | Facility : libnform
2049 | Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2052 | Description : If a character has been entered into a field, it may
2053 | be that wrapping has to occur. This routine checks
2054 | whether or not wrapping is required and if so, performs
2057 | Return Values : E_OK - no wrapping required or wrapping
2059 | E_REQUEST_DENIED -
2060 | E_SYSTEM_ERROR - some system error
2061 +--------------------------------------------------------------------------*/
2062 static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
2064 FIELD *field = form->current;
2065 int result = E_REQUEST_DENIED;
2066 bool Last_Row = ((field->drows - 1) == form->currow);
2068 if ( (field->opts & O_WRAP) && /* wrapping wanted */
2069 (!Single_Line_Field(field)) && /* must be multi-line */
2070 (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
2071 (!Last_Row || Growable(field)) ) /* there are more lines*/
2075 int chars_to_be_wrapped;
2076 int chars_to_remain_on_line;
2078 { /* the above logic already ensures, that in this case the field
2080 if (!Field_Grown(field,1))
2081 return E_SYSTEM_ERROR;
2083 bp = Address_Of_Current_Row_In_Buffer(form);
2084 Window_To_Buffer(form->w,field);
2085 split = After_Last_Whitespace_Character(bp,field->dcols);
2086 /* split points to the first character of the sequence to be brought
2088 chars_to_remain_on_line = (int)(split - bp);
2089 chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2090 if (chars_to_remain_on_line > 0)
2092 if ((result=Insert_String(form,form->currow+1,split,
2093 chars_to_be_wrapped)) == E_OK)
2095 wmove(form->w,form->currow,chars_to_remain_on_line);
2097 if (form->curcol >= chars_to_remain_on_line)
2100 form->curcol -= chars_to_remain_on_line;
2109 wmove(form->w,form->currow,form->curcol);
2111 Window_To_Buffer(form->w,field);
2112 result = E_REQUEST_DENIED;
2116 result = E_OK; /* wrapping was not necessary */
2120 /*----------------------------------------------------------------------------
2121 Field Editing routines
2122 --------------------------------------------------------------------------*/
2124 /*---------------------------------------------------------------------------
2125 | Facility : libnform
2126 | Function : static int Field_Editing(
2127 | int (* const fct) (FORM *),
2130 | Description : Generic routine for field editing requests. The driver
2131 | routines are only called for editable fields, the
2132 | _WINDOW_MODIFIED flag is set if editing occured.
2133 | This is somewhat special due to the overload semantics
2134 | of the NEW_LINE and DEL_PREV requests.
2136 | Return Values : Error code from low level drivers.
2137 +--------------------------------------------------------------------------*/
2138 static int Field_Editing(int (* const fct) (FORM *), FORM * form)
2140 int res = E_REQUEST_DENIED;
2142 /* We have to deal here with the specific case of the overloaded
2143 behaviour of New_Line and Delete_Previous requests.
2144 They may end up in navigational requests if we are on the first
2145 character in a field. But navigation is also allowed on non-
2148 if ((fct==FE_Delete_Previous) &&
2149 (form->opts & O_BS_OVERLOAD) &&
2150 First_Position_In_Current_Field(form) )
2152 res = Inter_Field_Navigation(FN_Previous_Field,form);
2156 if (fct==FE_New_Line)
2158 if ((form->opts & O_NL_OVERLOAD) &&
2159 First_Position_In_Current_Field(form))
2161 res = Inter_Field_Navigation(FN_Next_Field,form);
2164 /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2169 /* From now on, everything must be editable */
2170 if (form->current->opts & O_EDIT)
2174 form->status |= _WINDOW_MODIFIED;
2181 /*---------------------------------------------------------------------------
2182 | Facility : libnform
2183 | Function : static int FE_New_Line(FORM * form)
2185 | Description : Perform a new line request. This is rather complex
2186 | compared to other routines in this code due to the
2187 | rather difficult to understand description in the
2190 | Return Values : E_OK - success
2191 | E_REQUEST_DENIED - new line not allowed
2192 | E_SYSTEM_ERROR - system error
2193 +--------------------------------------------------------------------------*/
2194 static int FE_New_Line(FORM * form)
2196 FIELD *field = form->current;
2198 bool Last_Row = ((field->drows - 1)==form->currow);
2200 if (form->status & _OVLMODE)
2203 (!(Growable(field) && !Single_Line_Field(field))))
2205 if (!(form->opts & O_NL_OVERLOAD))
2206 return(E_REQUEST_DENIED);
2208 /* we have to set this here, although it is also
2209 handled in the generic routine. The reason is,
2210 that FN_Next_Field may fail, but the form is
2211 definitively changed */
2212 form->status |= _WINDOW_MODIFIED;
2213 return Inter_Field_Navigation(FN_Next_Field,form);
2217 if (Last_Row && !Field_Grown(field,1))
2218 { /* N.B.: due to the logic in the 'if', LastRow==TRUE
2219 means here that the field is growable and not
2220 a single-line field */
2221 return(E_SYSTEM_ERROR);
2226 form->status |= _WINDOW_MODIFIED;
2233 !(Growable(field) && !Single_Line_Field(field)))
2235 if (!(form->opts & O_NL_OVERLOAD))
2236 return(E_REQUEST_DENIED);
2237 return Inter_Field_Navigation(FN_Next_Field,form);
2241 bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2243 if (!(May_Do_It || Growable(field)))
2244 return(E_REQUEST_DENIED);
2245 if (!May_Do_It && !Field_Grown(field,1))
2246 return(E_SYSTEM_ERROR);
2248 bp= Address_Of_Current_Position_In_Buffer(form);
2249 t = After_End_Of_Data(bp,field->dcols - form->curcol);
2253 wmove(form->w,form->currow,form->curcol);
2255 waddnstr(form->w,bp,(int)(t-bp));
2256 form->status |= _WINDOW_MODIFIED;
2262 /*---------------------------------------------------------------------------
2263 | Facility : libnform
2264 | Function : static int FE_Insert_Character(FORM * form)
2266 | Description : Insert blank character at the cursor position
2268 | Return Values : E_OK
2270 +--------------------------------------------------------------------------*/
2271 static int FE_Insert_Character(FORM * form)
2273 FIELD *field = form->current;
2274 int result = E_REQUEST_DENIED;
2276 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2278 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2280 if (There_Is_Room ||
2281 ((Single_Line_Field(field) && Growable(field))))
2283 if (!There_Is_Room && !Field_Grown(field,1))
2284 result = E_SYSTEM_ERROR;
2287 winsch(form->w,(chtype)C_BLANK);
2288 result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2295 /*---------------------------------------------------------------------------
2296 | Facility : libnform
2297 | Function : static int FE_Insert_Line(FORM * form)
2299 | Description : Insert a blank line at the cursor position
2301 | Return Values : E_OK - success
2302 | E_REQUEST_DENIED - line can not be inserted
2303 +--------------------------------------------------------------------------*/
2304 static int FE_Insert_Line(FORM * form)
2306 FIELD *field = form->current;
2307 int result = E_REQUEST_DENIED;
2309 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2311 bool Maybe_Done = (form->currow!=(field->drows-1)) &&
2312 Is_There_Room_For_A_Line(form);
2314 if (!Single_Line_Field(field) &&
2315 (Maybe_Done || Growable(field)))
2317 if (!Maybe_Done && !Field_Grown(field,1))
2318 result = E_SYSTEM_ERROR;
2330 /*---------------------------------------------------------------------------
2331 | Facility : libnform
2332 | Function : static int FE_Delete_Character(FORM * form)
2334 | Description : Delete character at the cursor position
2336 | Return Values : E_OK - success
2337 +--------------------------------------------------------------------------*/
2338 static int FE_Delete_Character(FORM * form)
2344 /*---------------------------------------------------------------------------
2345 | Facility : libnform
2346 | Function : static int FE_Delete_Previous(FORM * form)
2348 | Description : Delete character before cursor. Again this is a rather
2349 | difficult piece compared to others due to the overloading
2350 | semantics of backspace.
2351 | N.B.: The case of overloaded BS on first field position
2352 | is already handled in the generic routine.
2354 | Return Values : E_OK - success
2355 | E_REQUEST_DENIED - Character can't be deleted
2356 +--------------------------------------------------------------------------*/
2357 static int FE_Delete_Previous(FORM * form)
2359 FIELD *field = form->current;
2361 if (First_Position_In_Current_Field(form))
2362 return E_REQUEST_DENIED;
2364 if ( (--(form->curcol))<0 )
2366 char *this_line, *prev_line, *prev_end, *this_end;
2369 if (form->status & _OVLMODE)
2370 return E_REQUEST_DENIED;
2372 prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
2373 this_line = Address_Of_Row_In_Buffer(field,(form->currow));
2374 Synchronize_Buffer(form);
2375 prev_end = After_End_Of_Data(prev_line,field->dcols);
2376 this_end = After_End_Of_Data(this_line,field->dcols);
2377 if ((int)(this_end-this_line) >
2378 (field->cols-(int)(prev_end-prev_line)))
2379 return E_REQUEST_DENIED;
2381 Adjust_Cursor_Position(form,prev_end);
2382 wmove(form->w,form->currow,form->curcol);
2383 waddnstr(form->w,this_line,(int)(this_end-this_line));
2387 wmove(form->w,form->currow,form->curcol);
2393 /*---------------------------------------------------------------------------
2394 | Facility : libnform
2395 | Function : static int FE_Delete_Line(FORM * form)
2397 | Description : Delete line at cursor position.
2399 | Return Values : E_OK - success
2400 +--------------------------------------------------------------------------*/
2401 static int FE_Delete_Line(FORM * form)
2408 /*---------------------------------------------------------------------------
2409 | Facility : libnform
2410 | Function : static int FE_Delete_Word(FORM * form)
2412 | Description : Delete word at cursor position
2414 | Return Values : E_OK - success
2415 | E_REQUEST_DENIED - failure
2416 +--------------------------------------------------------------------------*/
2417 static int FE_Delete_Word(FORM * form)
2419 FIELD *field = form->current;
2420 char *bp = Address_Of_Current_Row_In_Buffer(form);
2421 char *ep = bp + field->dcols;
2422 char *cp = bp + form->curcol;
2425 Synchronize_Buffer(form);
2427 return E_REQUEST_DENIED; /* not in word */
2429 /* move cursor to begin of word and erase to end of screen-line */
2430 Adjust_Cursor_Position(form,
2431 After_Last_Whitespace_Character(bp,form->curcol));
2432 wmove(form->w,form->currow,form->curcol);
2435 /* skip over word in buffer */
2436 s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
2437 /* to begin of next word */
2438 s = Get_Start_Of_Data(s,(int)(ep - s));
2439 if ( (s!=cp) && !is_blank(*s))
2441 /* copy remaining line to window */
2442 waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
2447 /*---------------------------------------------------------------------------
2448 | Facility : libnform
2449 | Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2451 | Description : Clear to end of current line.
2453 | Return Values : E_OK - success
2454 +--------------------------------------------------------------------------*/
2455 static int FE_Clear_To_End_Of_Line(FORM * form)
2461 /*---------------------------------------------------------------------------
2462 | Facility : libnform
2463 | Function : static int FE_Clear_To_End_Of_Form(FORM * form)
2465 | Description : Clear to end of form.
2467 | Return Values : E_OK - success
2468 +--------------------------------------------------------------------------*/
2469 static int FE_Clear_To_End_Of_Form(FORM * form)
2475 /*---------------------------------------------------------------------------
2476 | Facility : libnform
2477 | Function : static int FE_Clear_Field(FORM * form)
2479 | Description : Clear entire field.
2481 | Return Values : E_OK - success
2482 +--------------------------------------------------------------------------*/
2483 static int FE_Clear_Field(FORM * form)
2485 form->currow = form->curcol = 0;
2489 /*----------------------------------------------------------------------------
2490 END of Field Editing routines
2491 --------------------------------------------------------------------------*/
2493 /*----------------------------------------------------------------------------
2495 --------------------------------------------------------------------------*/
2497 /*---------------------------------------------------------------------------
2498 | Facility : libnform
2499 | Function : static int EM_Overlay_Mode(FORM * form)
2501 | Description : Switch to overlay mode.
2503 | Return Values : E_OK - success
2504 +--------------------------------------------------------------------------*/
2505 static int EM_Overlay_Mode(FORM * form)
2507 form->status |= _OVLMODE;
2511 /*---------------------------------------------------------------------------
2512 | Facility : libnform
2513 | Function : static int EM_Insert_Mode(FORM * form)
2515 | Description : Switch to insert mode
2517 | Return Values : E_OK - success
2518 +--------------------------------------------------------------------------*/
2519 static int EM_Insert_Mode(FORM * form)
2521 form->status &= ~_OVLMODE;
2525 /*----------------------------------------------------------------------------
2526 END of Edit Mode routines
2527 --------------------------------------------------------------------------*/
2529 /*----------------------------------------------------------------------------
2530 Helper routines for Choice Requests
2531 --------------------------------------------------------------------------*/
2533 /*---------------------------------------------------------------------------
2534 | Facility : libnform
2535 | Function : static bool Next_Choice(
2538 | TypeArgument *argp)
2540 | Description : Get the next field choice. For linked types this is
2543 | Return Values : TRUE - next choice successfully retrieved
2544 | FALSE - couldn't retrieve next choice
2545 +--------------------------------------------------------------------------*/
2546 static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
2548 if (!typ || !(typ->status & _HAS_CHOICE))
2551 if (typ->status & _LINKED_TYPE)
2555 Next_Choice(typ->left ,field,argp->left) ||
2556 Next_Choice(typ->right,field,argp->right) );
2561 return typ->next(field,(void *)argp);
2565 /*---------------------------------------------------------------------------
2566 | Facility : libnform
2567 | Function : static bool Previous_Choice(
2570 | TypeArgument *argp)
2572 | Description : Get the previous field choice. For linked types this
2573 | is done recursively.
2575 | Return Values : TRUE - previous choice successfully retrieved
2576 | FALSE - couldn't retrieve previous choice
2577 +--------------------------------------------------------------------------*/
2578 static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2580 if (!typ || !(typ->status & _HAS_CHOICE))
2583 if (typ->status & _LINKED_TYPE)
2587 Previous_Choice(typ->left ,field,argp->left) ||
2588 Previous_Choice(typ->right,field,argp->right));
2593 return typ->prev(field,(void *)argp);
2596 /*----------------------------------------------------------------------------
2597 End of Helper routines for Choice Requests
2598 --------------------------------------------------------------------------*/
2600 /*----------------------------------------------------------------------------
2601 Routines for Choice Requests
2602 --------------------------------------------------------------------------*/
2604 /*---------------------------------------------------------------------------
2605 | Facility : libnform
2606 | Function : static int CR_Next_Choice(FORM * form)
2608 | Description : Get the next field choice.
2610 | Return Values : E_OK - success
2611 | E_REQUEST_DENIED - next choice couldn't be retrieved
2612 +--------------------------------------------------------------------------*/
2613 static int CR_Next_Choice(FORM * form)
2615 FIELD *field = form->current;
2616 Synchronize_Buffer(form);
2617 return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2618 E_OK : E_REQUEST_DENIED);
2621 /*---------------------------------------------------------------------------
2622 | Facility : libnform
2623 | Function : static int CR_Previous_Choice(FORM * form)
2625 | Description : Get the previous field choice.
2627 | Return Values : E_OK - success
2628 | E_REQUEST_DENIED - prev. choice couldn't be retrieved
2629 +--------------------------------------------------------------------------*/
2630 static int CR_Previous_Choice(FORM * form)
2632 FIELD *field = form->current;
2633 Synchronize_Buffer(form);
2634 return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2635 E_OK : E_REQUEST_DENIED);
2637 /*----------------------------------------------------------------------------
2638 End of Routines for Choice Requests
2639 --------------------------------------------------------------------------*/
2641 /*----------------------------------------------------------------------------
2642 Helper routines for Field Validations.
2643 --------------------------------------------------------------------------*/
2645 /*---------------------------------------------------------------------------
2646 | Facility : libnform
2647 | Function : static bool Check_Field(
2650 | TypeArgument * argp)
2652 | Description : Check the field according to its fieldtype and its
2653 | actual arguments. For linked fieldtypes this is done
2656 | Return Values : TRUE - field is valid
2657 | FALSE - field is invalid.
2658 +--------------------------------------------------------------------------*/
2659 static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2663 if (field->opts & O_NULLOK)
2665 char *bp = field->buf;
2667 while(is_blank(*bp))
2673 if (typ->status & _LINKED_TYPE)
2677 Check_Field(typ->left ,field,argp->left ) ||
2678 Check_Field(typ->right,field,argp->right) );
2683 return typ->fcheck(field,(void *)argp);
2689 /*---------------------------------------------------------------------------
2690 | Facility : libnform
2691 | Function : bool _nc_Internal_Validation(FORM * form )
2693 | Description : Validate the current field of the form.
2695 | Return Values : TRUE - field is valid
2696 | FALSE - field is invalid
2697 +--------------------------------------------------------------------------*/
2698 NCURSES_EXPORT(bool)
2699 _nc_Internal_Validation (FORM *form)
2703 field = form->current;
2705 Synchronize_Buffer(form);
2706 if ((form->status & _FCHECK_REQUIRED) ||
2707 (!(field->opts & O_PASSOK)))
2709 if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
2711 form->status &= ~_FCHECK_REQUIRED;
2712 field->status |= _CHANGED;
2713 Synchronize_Linked_Fields(field);
2717 /*----------------------------------------------------------------------------
2718 End of Helper routines for Field Validations.
2719 --------------------------------------------------------------------------*/
2721 /*----------------------------------------------------------------------------
2722 Routines for Field Validation.
2723 --------------------------------------------------------------------------*/
2725 /*---------------------------------------------------------------------------
2726 | Facility : libnform
2727 | Function : static int FV_Validation(FORM * form)
2729 | Description : Validate the current field of the form.
2731 | Return Values : E_OK - field valid
2732 | E_INVALID_FIELD - field not valid
2733 +--------------------------------------------------------------------------*/
2734 static int FV_Validation(FORM * form)
2736 if (_nc_Internal_Validation(form))
2739 return E_INVALID_FIELD;
2741 /*----------------------------------------------------------------------------
2742 End of routines for Field Validation.
2743 --------------------------------------------------------------------------*/
2745 /*----------------------------------------------------------------------------
2746 Helper routines for Inter-Field Navigation
2747 --------------------------------------------------------------------------*/
2749 /*---------------------------------------------------------------------------
2750 | Facility : libnform
2751 | Function : static FIELD *Next_Field_On_Page(FIELD * field)
2753 | Description : Get the next field after the given field on the current
2754 | page. The order of fields is the one defined by the
2755 | fields array. Only visible and active fields are
2758 | Return Values : Pointer to the next field.
2759 +--------------------------------------------------------------------------*/
2760 INLINE static FIELD *Next_Field_On_Page(FIELD * field)
2762 FORM *form = field->form;
2763 FIELD **field_on_page = &form->field[field->index];
2764 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2765 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2770 (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
2771 if (Field_Is_Selectable(*field_on_page))
2773 } while(field!=(*field_on_page));
2774 return(*field_on_page);
2777 /*---------------------------------------------------------------------------
2778 | Facility : libnform
2779 | Function : FIELD* _nc_First_Active_Field(FORM * form)
2781 | Description : Get the first active field on the current page,
2782 | if there are such. If there are none, get the first
2783 | visible field on the page. If there are also none,
2784 | we return the first field on page and hope the best.
2786 | Return Values : Pointer to calculated field.
2787 +--------------------------------------------------------------------------*/
2788 NCURSES_EXPORT(FIELD*)
2789 _nc_First_Active_Field (FORM * form)
2791 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2792 FIELD *proposed = Next_Field_On_Page(*last_on_page);
2794 if (proposed == *last_on_page)
2795 { /* there might be the special situation, where there is no
2796 active and visible field on the current page. We then select
2797 the first visible field on this readonly page
2799 if (Field_Is_Not_Selectable(proposed))
2801 FIELD **field = &form->field[proposed->index];
2802 FIELD **first = &form->field[form->page[form->curpage].pmin];
2806 field = (field==last_on_page) ? first : field + 1;
2807 if (((*field)->opts & O_VISIBLE))
2809 } while(proposed!=(*field));
2813 if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
2814 { /* This means, there is also no visible field on the page.
2815 So we propose the first one and hope the very best...
2816 Some very clever user has designed a readonly and invisible
2826 /*---------------------------------------------------------------------------
2827 | Facility : libnform
2828 | Function : static FIELD *Previous_Field_On_Page(FIELD * field)
2830 | Description : Get the previous field before the given field on the
2831 | current page. The order of fields is the one defined by
2832 | the fields array. Only visible and active fields are
2835 | Return Values : Pointer to the previous field.
2836 +--------------------------------------------------------------------------*/
2837 INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
2839 FORM *form = field->form;
2840 FIELD **field_on_page = &form->field[field->index];
2841 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2842 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2847 (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
2848 if (Field_Is_Selectable(*field_on_page))
2850 } while(field!=(*field_on_page));
2852 return (*field_on_page);
2855 /*---------------------------------------------------------------------------
2856 | Facility : libnform
2857 | Function : static FIELD *Sorted_Next_Field(FIELD * field)
2859 | Description : Get the next field after the given field on the current
2860 | page. The order of fields is the one defined by the
2861 | (row,column) geometry, rows are major.
2863 | Return Values : Pointer to the next field.
2864 +--------------------------------------------------------------------------*/
2865 INLINE static FIELD *Sorted_Next_Field(FIELD * field)
2867 FIELD *field_on_page = field;
2871 field_on_page = field_on_page->snext;
2872 if (Field_Is_Selectable(field_on_page))
2874 } while(field_on_page!=field);
2876 return (field_on_page);
2879 /*---------------------------------------------------------------------------
2880 | Facility : libnform
2881 | Function : static FIELD *Sorted_Previous_Field(FIELD * field)
2883 | Description : Get the previous field before the given field on the
2884 | current page. The order of fields is the one defined
2885 | by the (row,column) geometry, rows are major.
2887 | Return Values : Pointer to the previous field.
2888 +--------------------------------------------------------------------------*/
2889 INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
2891 FIELD *field_on_page = field;
2895 field_on_page = field_on_page->sprev;
2896 if (Field_Is_Selectable(field_on_page))
2898 } while(field_on_page!=field);
2900 return (field_on_page);
2903 /*---------------------------------------------------------------------------
2904 | Facility : libnform
2905 | Function : static FIELD *Left_Neighbour_Field(FIELD * field)
2907 | Description : Get the left neighbour of the field on the same line
2908 | and the same page. Cycles through the line.
2910 | Return Values : Pointer to left neighbour field.
2911 +--------------------------------------------------------------------------*/
2912 INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
2914 FIELD *field_on_page = field;
2916 /* For a field that has really a left neighbour, the while clause
2917 immediately fails and the loop is left, positioned at the right
2918 neighbour. Otherwise we cycle backwards through the sorted fieldlist
2919 until we enter the same line (from the right end).
2923 field_on_page = Sorted_Previous_Field(field_on_page);
2924 } while(field_on_page->frow != field->frow);
2926 return (field_on_page);
2929 /*---------------------------------------------------------------------------
2930 | Facility : libnform
2931 | Function : static FIELD *Right_Neighbour_Field(FIELD * field)
2933 | Description : Get the right neighbour of the field on the same line
2934 | and the same page.
2936 | Return Values : Pointer to right neighbour field.
2937 +--------------------------------------------------------------------------*/
2938 INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
2940 FIELD *field_on_page = field;
2942 /* See the comments on Left_Neighbour_Field to understand how it works */
2945 field_on_page = Sorted_Next_Field(field_on_page);
2946 } while(field_on_page->frow != field->frow);
2948 return (field_on_page);
2951 /*---------------------------------------------------------------------------
2952 | Facility : libnform
2953 | Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
2955 | Description : Because of the row-major nature of sorting the fields,
2956 | its more difficult to define whats the upper neighbour
2957 | field really means. We define that it must be on a
2958 | 'previous' line (cyclic order!) and is the rightmost
2959 | field laying on the left side of the given field. If
2960 | this set is empty, we take the first field on the line.
2962 | Return Values : Pointer to the upper neighbour field.
2963 +--------------------------------------------------------------------------*/
2964 static FIELD *Upper_Neighbour_Field(FIELD * field)
2966 FIELD *field_on_page = field;
2967 int frow = field->frow;
2968 int fcol = field->fcol;
2970 /* Walk back to the 'previous' line. The second term in the while clause
2971 just guarantees that we stop if we cycled through the line because
2972 there might be no 'previous' line if the page has just one line.
2976 field_on_page = Sorted_Previous_Field(field_on_page);
2977 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
2979 if (field_on_page->frow!=frow)
2980 { /* We really found a 'previous' line. We are positioned at the
2981 rightmost field on this line */
2982 frow = field_on_page->frow;
2984 /* We walk to the left as long as we are really right of the
2986 while(field_on_page->frow==frow && field_on_page->fcol>fcol)
2987 field_on_page = Sorted_Previous_Field(field_on_page);
2989 /* If we wrapped, just go to the right which is the first field on
2991 if (field_on_page->frow!=frow)
2992 field_on_page = Sorted_Next_Field(field_on_page);
2995 return (field_on_page);
2998 /*---------------------------------------------------------------------------
2999 | Facility : libnform
3000 | Function : static FIELD *Down_Neighbour_Field(FIELD * field)
3002 | Description : Because of the row-major nature of sorting the fields,
3003 | its more difficult to define whats the down neighbour
3004 | field really means. We define that it must be on a
3005 | 'next' line (cyclic order!) and is the leftmost
3006 | field laying on the right side of the given field. If
3007 | this set is empty, we take the last field on the line.
3009 | Return Values : Pointer to the upper neighbour field.
3010 +--------------------------------------------------------------------------*/
3011 static FIELD *Down_Neighbour_Field(FIELD * field)
3013 FIELD *field_on_page = field;
3014 int frow = field->frow;
3015 int fcol = field->fcol;
3017 /* Walk forward to the 'next' line. The second term in the while clause
3018 just guarantees that we stop if we cycled through the line because
3019 there might be no 'next' line if the page has just one line.
3023 field_on_page = Sorted_Next_Field(field_on_page);
3024 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3026 if (field_on_page->frow!=frow)
3027 { /* We really found a 'next' line. We are positioned at the rightmost
3028 field on this line */
3029 frow = field_on_page->frow;
3031 /* We walk to the right as long as we are really left of the
3033 while(field_on_page->frow==frow && field_on_page->fcol<fcol)
3034 field_on_page = Sorted_Next_Field(field_on_page);
3036 /* If we wrapped, just go to the left which is the last field on
3038 if (field_on_page->frow!=frow)
3039 field_on_page = Sorted_Previous_Field(field_on_page);
3042 return(field_on_page);
3045 /*----------------------------------------------------------------------------
3046 Inter-Field Navigation routines
3047 --------------------------------------------------------------------------*/
3049 /*---------------------------------------------------------------------------
3050 | Facility : libnform
3051 | Function : static int Inter_Field_Navigation(
3052 | int (* const fct) (FORM *),
3055 | Description : Generic behaviour for changing the current field, the
3056 | field is left and a new field is entered. So the field
3057 | must be validated and the field init/term hooks must
3060 | Return Values : E_OK - success
3061 | E_INVALID_FIELD - field is invalid
3062 | some other - error from subordinate call
3063 +--------------------------------------------------------------------------*/
3064 static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
3068 if (!_nc_Internal_Validation(form))
3069 res = E_INVALID_FIELD;
3072 Call_Hook(form,fieldterm);
3074 Call_Hook(form,fieldinit);
3079 /*---------------------------------------------------------------------------
3080 | Facility : libnform
3081 | Function : static int FN_Next_Field(FORM * form)
3083 | Description : Move to the next field on the current page of the form
3085 | Return Values : E_OK - success
3086 | != E_OK - error from subordinate call
3087 +--------------------------------------------------------------------------*/
3088 static int FN_Next_Field(FORM * form)
3090 return _nc_Set_Current_Field(form,
3091 Next_Field_On_Page(form->current));
3094 /*---------------------------------------------------------------------------
3095 | Facility : libnform
3096 | Function : static int FN_Previous_Field(FORM * form)
3098 | Description : Move to the previous field on the current page of the
3101 | Return Values : E_OK - success
3102 | != E_OK - error from subordinate call
3103 +--------------------------------------------------------------------------*/
3104 static int FN_Previous_Field(FORM * form)
3106 return _nc_Set_Current_Field(form,
3107 Previous_Field_On_Page(form->current));
3110 /*---------------------------------------------------------------------------
3111 | Facility : libnform
3112 | Function : static int FN_First_Field(FORM * form)
3114 | Description : Move to the first field on the current page of the form
3116 | Return Values : E_OK - success
3117 | != E_OK - error from subordinate call
3118 +--------------------------------------------------------------------------*/
3119 static int FN_First_Field(FORM * form)
3121 return _nc_Set_Current_Field(form,
3122 Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
3125 /*---------------------------------------------------------------------------
3126 | Facility : libnform
3127 | Function : static int FN_Last_Field(FORM * form)
3129 | Description : Move to the last field on the current page of the form
3131 | Return Values : E_OK - success
3132 | != E_OK - error from subordinate call
3133 +--------------------------------------------------------------------------*/
3134 static int FN_Last_Field(FORM * form)
3137 _nc_Set_Current_Field(form,
3138 Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
3141 /*---------------------------------------------------------------------------
3142 | Facility : libnform
3143 | Function : static int FN_Sorted_Next_Field(FORM * form)
3145 | Description : Move to the sorted next field on the current page
3148 | Return Values : E_OK - success
3149 | != E_OK - error from subordinate call
3150 +--------------------------------------------------------------------------*/
3151 static int FN_Sorted_Next_Field(FORM * form)
3153 return _nc_Set_Current_Field(form,
3154 Sorted_Next_Field(form->current));
3157 /*---------------------------------------------------------------------------
3158 | Facility : libnform
3159 | Function : static int FN_Sorted_Previous_Field(FORM * form)
3161 | Description : Move to the sorted previous field on the current page
3164 | Return Values : E_OK - success
3165 | != E_OK - error from subordinate call
3166 +--------------------------------------------------------------------------*/
3167 static int FN_Sorted_Previous_Field(FORM * form)
3169 return _nc_Set_Current_Field(form,
3170 Sorted_Previous_Field(form->current));
3173 /*---------------------------------------------------------------------------
3174 | Facility : libnform
3175 | Function : static int FN_Sorted_First_Field(FORM * form)
3177 | Description : Move to the sorted first field on the current page
3180 | Return Values : E_OK - success
3181 | != E_OK - error from subordinate call
3182 +--------------------------------------------------------------------------*/
3183 static int FN_Sorted_First_Field(FORM * form)
3185 return _nc_Set_Current_Field(form,
3186 Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
3189 /*---------------------------------------------------------------------------
3190 | Facility : libnform
3191 | Function : static int FN_Sorted_Last_Field(FORM * form)
3193 | Description : Move to the sorted last field on the current page
3196 | Return Values : E_OK - success
3197 | != E_OK - error from subordinate call
3198 +--------------------------------------------------------------------------*/
3199 static int FN_Sorted_Last_Field(FORM * form)
3201 return _nc_Set_Current_Field(form,
3202 Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
3205 /*---------------------------------------------------------------------------
3206 | Facility : libnform
3207 | Function : static int FN_Left_Field(FORM * form)
3209 | Description : Get the field on the left of the current field on the
3210 | same line and the same page. Cycles through the line.
3212 | Return Values : E_OK - success
3213 | != E_OK - error from subordinate call
3214 +--------------------------------------------------------------------------*/
3215 static int FN_Left_Field(FORM * form)
3217 return _nc_Set_Current_Field(form,
3218 Left_Neighbour_Field(form->current));
3221 /*---------------------------------------------------------------------------
3222 | Facility : libnform
3223 | Function : static int FN_Right_Field(FORM * form)
3225 | Description : Get the field on the right of the current field on the
3226 | same line and the same page. Cycles through the line.
3228 | Return Values : E_OK - success
3229 | != E_OK - error from subordinate call
3230 +--------------------------------------------------------------------------*/
3231 static int FN_Right_Field(FORM * form)
3233 return _nc_Set_Current_Field(form,
3234 Right_Neighbour_Field(form->current));
3237 /*---------------------------------------------------------------------------
3238 | Facility : libnform
3239 | Function : static int FN_Up_Field(FORM * form)
3241 | Description : Get the upper neighbour of the current field. This
3242 | cycles through the page. See the comments of the
3243 | Upper_Neighbour_Field function to understand how
3244 | 'upper' is defined.
3246 | Return Values : E_OK - success
3247 | != E_OK - error from subordinate call
3248 +--------------------------------------------------------------------------*/
3249 static int FN_Up_Field(FORM * form)
3251 return _nc_Set_Current_Field(form,
3252 Upper_Neighbour_Field(form->current));
3255 /*---------------------------------------------------------------------------
3256 | Facility : libnform
3257 | Function : static int FN_Down_Field(FORM * form)
3259 | Description : Get the down neighbour of the current field. This
3260 | cycles through the page. See the comments of the
3261 | Down_Neighbour_Field function to understand how
3262 | 'down' is defined.
3264 | Return Values : E_OK - success
3265 | != E_OK - error from subordinate call
3266 +--------------------------------------------------------------------------*/
3267 static int FN_Down_Field(FORM * form)
3269 return _nc_Set_Current_Field(form,
3270 Down_Neighbour_Field(form->current));
3272 /*----------------------------------------------------------------------------
3273 END of Field Navigation routines
3274 --------------------------------------------------------------------------*/
3276 /*----------------------------------------------------------------------------
3277 Helper routines for Page Navigation
3278 --------------------------------------------------------------------------*/
3280 /*---------------------------------------------------------------------------
3281 | Facility : libnform
3282 | Function : int _nc_Set_Form_Page(FORM * form,
3286 | Description : Make the given page nr. the current page and make
3287 | the given field the current field on the page. If
3288 | for the field NULL is given, make the first field on
3289 | the page the current field. The routine acts only
3290 | if the requested page is not the current page.
3292 | Return Values : E_OK - success
3293 | != E_OK - error from subordinate call
3294 +--------------------------------------------------------------------------*/
3297 (FORM * form, int page, FIELD * field)
3301 if ((form->curpage!=page))
3303 FIELD *last_field, *field_on_page;
3305 werase(Get_Form_Window(form));
3306 form->curpage = page;
3307 last_field = field_on_page = form->field[form->page[page].smin];
3310 if (field_on_page->opts & O_VISIBLE)
3311 if ((res=Display_Field(field_on_page))!=E_OK)
3313 field_on_page = field_on_page->snext;
3314 } while(field_on_page != last_field);
3317 res = _nc_Set_Current_Field(form,field);
3319 /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
3320 because this is already executed in a page navigation
3321 context that contains field navigation
3323 res = FN_First_Field(form);
3328 /*---------------------------------------------------------------------------
3329 | Facility : libnform
3330 | Function : static int Next_Page_Number(const FORM * form)
3332 | Description : Calculate the page number following the current page
3333 | number. This cycles if the highest page number is
3336 | Return Values : The next page number
3337 +--------------------------------------------------------------------------*/
3338 INLINE static int Next_Page_Number(const FORM * form)
3340 return (form->curpage + 1) % form->maxpage;
3343 /*---------------------------------------------------------------------------
3344 | Facility : libnform
3345 | Function : static int Previous_Page_Number(const FORM * form)
3347 | Description : Calculate the page number before the current page
3348 | number. This cycles if the first page number is
3351 | Return Values : The previous page number
3352 +--------------------------------------------------------------------------*/
3353 INLINE static int Previous_Page_Number(const FORM * form)
3355 return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
3358 /*----------------------------------------------------------------------------
3359 Page Navigation routines
3360 --------------------------------------------------------------------------*/
3362 /*---------------------------------------------------------------------------
3363 | Facility : libnform
3364 | Function : static int Page_Navigation(
3365 | int (* const fct) (FORM *),
3368 | Description : Generic behaviour for changing a page. This means
3369 | that the field is left and a new field is entered.
3370 | So the field must be validated and the field init/term
3371 | hooks must be called. Because also the page is changed,
3372 | the forms init/term hooks must be called also.
3374 | Return Values : E_OK - success
3375 | E_INVALID_FIELD - field is invalid
3376 | some other - error from subordinate call
3377 +--------------------------------------------------------------------------*/
3378 static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
3382 if (!_nc_Internal_Validation(form))
3383 res = E_INVALID_FIELD;
3386 Call_Hook(form,fieldterm);
3387 Call_Hook(form,formterm);
3389 Call_Hook(form,forminit);
3390 Call_Hook(form,fieldinit);
3395 /*---------------------------------------------------------------------------
3396 | Facility : libnform
3397 | Function : static int PN_Next_Page(FORM * form)
3399 | Description : Move to the next page of the form
3401 | Return Values : E_OK - success
3402 | != E_OK - error from subordinate call
3403 +--------------------------------------------------------------------------*/
3404 static int PN_Next_Page(FORM * form)
3406 return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
3409 /*---------------------------------------------------------------------------
3410 | Facility : libnform
3411 | Function : static int PN_Previous_Page(FORM * form)
3413 | Description : Move to the previous page of the form
3415 | Return Values : E_OK - success
3416 | != E_OK - error from subordinate call
3417 +--------------------------------------------------------------------------*/
3418 static int PN_Previous_Page(FORM * form)
3420 return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
3423 /*---------------------------------------------------------------------------
3424 | Facility : libnform
3425 | Function : static int PN_First_Page(FORM * form)
3427 | Description : Move to the first page of the form
3429 | Return Values : E_OK - success
3430 | != E_OK - error from subordinate call
3431 +--------------------------------------------------------------------------*/
3432 static int PN_First_Page(FORM * form)
3434 return _nc_Set_Form_Page(form,0,(FIELD *)0);
3437 /*---------------------------------------------------------------------------
3438 | Facility : libnform
3439 | Function : static int PN_Last_Page(FORM * form)
3441 | Description : Move to the last page of the form
3443 | Return Values : E_OK - success
3444 | != E_OK - error from subordinate call
3445 +--------------------------------------------------------------------------*/
3446 static int PN_Last_Page(FORM * form)
3448 return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
3450 /*----------------------------------------------------------------------------
3451 END of Field Navigation routines
3452 --------------------------------------------------------------------------*/
3454 /*----------------------------------------------------------------------------
3455 Helper routines for the core form driver.
3456 --------------------------------------------------------------------------*/
3458 /*---------------------------------------------------------------------------
3459 | Facility : libnform
3460 | Function : static int Data_Entry(FORM * form,int c)
3462 | Description : Enter character c into at the current position of the
3463 | current field of the form.
3465 | Return Values : E_OK -
3466 | E_REQUEST_DENIED -
3468 +--------------------------------------------------------------------------*/
3469 static int Data_Entry(FORM * form, int c)
3471 FIELD *field = form->current;
3472 int result = E_REQUEST_DENIED;
3474 if ( (field->opts & O_EDIT)
3475 #if FIX_FORM_INACTIVE_BUG
3476 && (field->opts & O_ACTIVE)
3480 if ( (field->opts & O_BLANK) &&
3481 First_Position_In_Current_Field(form) &&
3482 !(form->status & _FCHECK_REQUIRED) &&
3483 !(form->status & _WINDOW_MODIFIED) )
3486 if (form->status & _OVLMODE)
3488 waddch(form->w,(chtype)c);
3490 else /* no _OVLMODE */
3492 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
3494 if (!(There_Is_Room ||
3495 ((Single_Line_Field(field) && Growable(field)))))
3496 return E_REQUEST_DENIED;
3498 if (!There_Is_Room && !Field_Grown(field,1))
3499 return E_SYSTEM_ERROR;
3501 winsch(form->w,(chtype)c);
3504 if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
3506 bool End_Of_Field= (((field->drows-1)==form->currow) &&
3507 ((field->dcols-1)==form->curcol));
3508 form->status |= _WINDOW_MODIFIED;
3509 if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3510 result = Inter_Field_Navigation(FN_Next_Field,form);
3513 if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
3514 result = E_SYSTEM_ERROR;
3517 IFN_Next_Character(form);
3526 /* Structure to describe the binding of a request code to a function.
3527 The member keycode codes the request value as well as the generic
3528 routine to use for the request. The code for the generic routine
3529 is coded in the upper 16 Bits while the request code is coded in
3532 In terms of C++ you might think of a request as a class with a
3533 virtual method "perform". The different types of request are
3534 derived from this base class and overload (or not) the base class
3535 implementation of perform.
3538 int keycode; /* must be at least 32 bit: hi:mode, lo: key */
3539 int (*cmd)(FORM *); /* low level driver routine for this key */
3542 /* You may see this is the class-id of the request type class */
3543 #define ID_PN (0x00000000) /* Page navigation */
3544 #define ID_FN (0x00010000) /* Inter-Field navigation */
3545 #define ID_IFN (0x00020000) /* Intra-Field navigation */
3546 #define ID_VSC (0x00030000) /* Vertical Scrolling */
3547 #define ID_HSC (0x00040000) /* Horizontal Scrolling */
3548 #define ID_FE (0x00050000) /* Field Editing */
3549 #define ID_EM (0x00060000) /* Edit Mode */
3550 #define ID_FV (0x00070000) /* Field Validation */
3551 #define ID_CH (0x00080000) /* Choice */
3552 #define ID_Mask (0xffff0000)
3553 #define Key_Mask (0x0000ffff)
3554 #define ID_Shft (16)
3556 /* This array holds all the Binding Infos */
3557 static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
3559 { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
3560 { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
3561 { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
3562 { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
3564 { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
3565 { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
3566 { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
3567 { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
3568 { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
3569 { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
3570 { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
3571 { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
3572 { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
3573 { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
3574 { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
3575 { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
3577 { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
3578 { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
3579 { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
3580 { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
3581 { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
3582 { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
3583 { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
3584 { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
3585 { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
3586 { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
3587 { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
3588 { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
3589 { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
3590 { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
3592 { REQ_NEW_LINE |ID_FE ,FE_New_Line},
3593 { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
3594 { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
3595 { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
3596 { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
3597 { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
3598 { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
3599 { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
3600 { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
3601 { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
3603 { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
3604 { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
3606 { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
3607 { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
3608 { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
3609 { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
3610 { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
3611 { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
3613 { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
3614 { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
3615 { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
3616 { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
3617 { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
3618 { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
3620 { REQ_VALIDATION |ID_FV ,FV_Validation},
3622 { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
3623 { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
3626 /*---------------------------------------------------------------------------
3627 | Facility : libnform
3628 | Function : int form_driver(FORM * form,int c)
3630 | Description : This is the workhorse of the forms system. It checks
3631 | to determine whether the character c is a request or
3632 | data. If it is a request, the form driver executes
3633 | the request and returns the result. If it is data
3634 | (printable character), it enters the data into the
3635 | current position in the current field. If it is not
3636 | recognized, the form driver assumes it is an application
3637 | defined command and returns E_UNKNOWN_COMMAND.
3638 | Application defined command should be defined relative
3639 | to MAX_FORM_COMMAND, the maximum value of a request.
3641 | Return Values : E_OK - success
3642 | E_SYSTEM_ERROR - system error
3643 | E_BAD_ARGUMENT - an argument is incorrect
3644 | E_NOT_POSTED - form is not posted
3645 | E_INVALID_FIELD - field contents are invalid
3646 | E_BAD_STATE - called from inside a hook routine
3647 | E_REQUEST_DENIED - request failed
3648 | E_UNKNOWN_COMMAND - command not known
3649 +--------------------------------------------------------------------------*/
3651 form_driver (FORM * form, int c)
3653 const Binding_Info* BI = (Binding_Info *)0;
3654 int res = E_UNKNOWN_COMMAND;
3657 RETURN(E_BAD_ARGUMENT);
3660 RETURN(E_NOT_CONNECTED);
3664 if (c==FIRST_ACTIVE_MAGIC)
3666 form->current = _nc_First_Active_Field(form);
3670 assert(form->current &&
3671 form->current->buf &&
3672 (form->current->form == form)
3675 if ( form->status & _IN_DRIVER )
3676 RETURN(E_BAD_STATE);
3678 if ( !( form->status & _POSTED ) )
3679 RETURN(E_NOT_POSTED);
3681 if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
3682 ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
3683 BI = &(bindings[c-MIN_FORM_COMMAND]);
3687 typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
3688 static const Generic_Method Generic_Methods[] =
3690 Page_Navigation, /* overloaded to call field&form hooks */
3691 Inter_Field_Navigation, /* overloaded to call field hooks */
3692 NULL, /* Intra-Field is generic */
3693 Vertical_Scrolling, /* Overloaded to check multi-line */
3694 Horizontal_Scrolling, /* Overloaded to check single-line */
3695 Field_Editing, /* Overloaded to mark modification */
3696 NULL, /* Edit Mode is generic */
3697 NULL, /* Field Validation is generic */
3698 NULL /* Choice Request is generic */
3700 size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
3701 size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
3703 if ( (method >= nMethods) || !(BI->cmd) )
3704 res = E_SYSTEM_ERROR;
3707 Generic_Method fct = Generic_Methods[method];
3709 res = fct(BI->cmd,form);
3711 res = (BI->cmd)(form);
3716 if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
3717 isprint((unsigned char)c) &&
3718 Check_Char(form->current->type,c,
3719 (TypeArgument *)(form->current->arg)))
3720 res = Data_Entry(form,c);
3722 _nc_Refresh_Current_Field(form);
3726 /*----------------------------------------------------------------------------
3727 Field-Buffer manipulation routines.
3728 The effects of setting a buffer is tightly coupled to the core of the form
3729 driver logic. This is especially true in the case of growable fields.
3730 So I don't separate this into an own module.
3731 --------------------------------------------------------------------------*/
3733 /*---------------------------------------------------------------------------
3734 | Facility : libnform
3735 | Function : int set_field_buffer(FIELD *field,
3736 | int buffer, char *value)
3738 | Description : Set the given buffer of the field to the given value.
3739 | Buffer 0 stores the displayed content of the field.
3740 | For dynamic fields this may grow the fieldbuffers if
3741 | the length of the value exceeds the current buffer
3742 | length. For buffer 0 only printable values are allowed.
3743 | For static fields, the value needs not to be zero ter-
3744 | minated. It is copied up to the length of the buffer.
3746 | Return Values : E_OK - success
3747 | E_BAD_ARGUMENT - invalid argument
3748 | E_SYSTEM_ERROR - system error
3749 +--------------------------------------------------------------------------*/
3752 (FIELD * field, int buffer, const char * value)
3758 if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
3759 RETURN(E_BAD_ARGUMENT);
3761 len = Buffer_Length(field);
3768 for(v=value; *v && (i<len); v++,i++)
3770 if (!isprint((unsigned char)*v))
3771 RETURN(E_BAD_ARGUMENT);
3775 if (Growable(field))
3777 /* for a growable field we must assume zero terminated strings, because
3778 somehow we have to detect the length of what should be copied.
3780 unsigned int vlen = strlen(value);
3783 if (!Field_Grown(field,
3784 (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
3785 RETURN(E_SYSTEM_ERROR);
3787 /* in this case we also have to check, wether or not the remaining
3788 characters in value are also printable for buffer 0. */
3793 for(i=len; i<vlen; i++)
3794 if (!isprint((unsigned char)value[i]))
3795 RETURN(E_BAD_ARGUMENT);
3801 p = Address_Of_Nth_Buffer(field,buffer);
3804 s = memccpy(p,value,0,len);
3806 for(s=(char *)value; *s && (s < (value+len)); s++)
3808 if (s < (value+len))
3818 { /* this means, value was null terminated and not greater than the
3819 buffer. We have to pad with blanks. Please note that due to memccpy
3820 logic s points after the terminating null. */
3821 s--; /* now we point to the terminator. */
3822 assert(len >= (unsigned int)(s-p));
3823 if (len > (unsigned int)(s-p))
3824 memset(s,C_BLANK,len-(unsigned int)(s-p));
3830 if (((syncres=Synchronize_Field( field ))!=E_OK) &&
3833 if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
3840 /*---------------------------------------------------------------------------
3841 | Facility : libnform
3842 | Function : char *field_buffer(const FIELD *field,int buffer)
3844 | Description : Return the address of the buffer for the field.
3846 | Return Values : Pointer to buffer or NULL if arguments were invalid.
3847 +--------------------------------------------------------------------------*/
3848 NCURSES_EXPORT(char *)
3849 field_buffer (const FIELD * field, int buffer)
3851 if (field && (buffer >= 0) && (buffer <= field->nbuf))
3852 return Address_Of_Nth_Buffer(field,buffer);
3857 /* frm_driver.c ends here */