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, 1995,1997 *
31 * Contact: http://www.familiepfeifer.de/Contact.aspx?Lang=en *
32 ****************************************************************************/
33 #include "form.priv.h"
35 MODULE_ID("$Id: frm_driver.c,v 1.39 2002/07/06 15:33:27 juergen Exp $")
37 /*----------------------------------------------------------------------------
38 This is the core module of the form library. It contains the majority
39 of the driver routines as well as the form_driver function.
41 Essentially this module is nearly the whole library. This is because
42 all the functions in this module depends on some others in the module,
43 so it makes no sense to split them into separate files because they
44 will always be linked together. The only acceptable concern is turnaround
45 time for this module, but now we have all Pentiums or Riscs, so what!
47 The driver routines are grouped into nine generic categories:
49 a) Page Navigation ( all functions prefixed by PN_ )
50 The current page of the form is left and some new page is
52 b) Inter-Field Navigation ( all functions prefixed by FN_ )
53 The current field of the form is left and some new field is
55 c) Intra-Field Navigation ( all functions prefixed by IFN_ )
56 The current position in the current field is changed.
57 d) Vertical Scrolling ( all functions prefixed by VSC_ )
58 Esseantially this is a specialization of Intra-Field navigation.
59 It has to check for a multi-line field.
60 e) Horizontal Scrolling ( all functions prefixed by HSC_ )
61 Esseantially this is a specialization of Intra-Field navigation.
62 It has to check for a single-line field.
63 f) Field Editing ( all functions prefixed by FE_ )
64 The content of the current field is changed
65 g) Edit Mode requests ( all functions prefixed by EM_ )
66 Switching between insert and overlay mode
67 h) Field-Validation requests ( all functions prefixed by FV_ )
68 Perform verifications of the field.
69 i) Choice requests ( all functions prefixed by CR_ )
70 Requests to enumerate possible field values
71 --------------------------------------------------------------------------*/
73 /*----------------------------------------------------------------------------
74 Some remarks on the placements of assert() macros :
75 I use them only on "strategic" places, i.e. top level entries where
76 I want to make sure that things are set correctly. Throughout subordinate
77 routines I omit them mostly.
78 --------------------------------------------------------------------------*/
81 Some options that may effect compatibility in behavior to SVr4 forms,
82 but they are here to allow a more intuitive and user friendly behaviour of
83 our form implementation. This doesn't affect the API, so we feel it is
86 The initial implementation tries to stay very close with the behaviour
87 of the original SVr4 implementation, although in some areas it is quite
88 clear that this isn't the most appropriate way. As far as possible this
89 sources will allow you to build a forms lib that behaves quite similar
90 to SVr4, but now and in the future we will give you better options.
91 Perhaps at some time we will make this configurable at runtime.
94 /* Implement a more user-friendly previous/next word behaviour */
95 #define FRIENDLY_PREV_NEXT_WORD (1)
96 /* Fix the wrong behaviour for forms with all fields inactive */
97 #define FIX_FORM_INACTIVE_BUG (1)
98 /* Allow dynamic field growth also when navigating past the end */
99 #define GROW_IF_NAVIGATE (1)
101 /*----------------------------------------------------------------------------
102 Forward references to some internally used static functions
103 --------------------------------------------------------------------------*/
104 static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
105 static int FN_Next_Field (FORM * form);
106 static int FN_Previous_Field (FORM * form);
107 static int FE_New_Line(FORM *);
108 static int FE_Delete_Previous(FORM *);
110 /*----------------------------------------------------------------------------
113 Some Remarks on that: I use the convention to use UPPERCASE for constants
114 defined by Macros. If I provide a macro as a kind of inline routine to
115 provide some logic, I use my Upper_Lower case style.
116 --------------------------------------------------------------------------*/
118 /* Calculate the position of a single row in a field buffer */
119 #define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
121 /* Calculate start address for the fields buffer# N */
122 #define Address_Of_Nth_Buffer(field,N) \
123 ((field)->buf + (N)*(1+Buffer_Length(field)))
125 /* Calculate the start address of the row in the fields specified buffer# N */
126 #define Address_Of_Row_In_Nth_Buffer(field,N,row) \
127 (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
129 /* Calculate the start address of the row in the fields primary buffer */
130 #define Address_Of_Row_In_Buffer(field,row) \
131 Address_Of_Row_In_Nth_Buffer(field,0,row)
133 /* Calculate the start address of the row in the forms current field
135 #define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
136 Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
138 /* Calculate the start address of the row in the forms current field
140 #define Address_Of_Current_Row_In_Buffer(form) \
141 Address_Of_Current_Row_In_Nth_Buffer(form,0)
143 /* Calculate the address of the cursor in the forms current field
145 #define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
146 (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
148 /* Calculate the address of the cursor in the forms current field
150 #define Address_Of_Current_Position_In_Buffer(form) \
151 Address_Of_Current_Position_In_Nth_Buffer(form,0)
153 /* Logic to decide wether or not a field is actually a field with
154 vertical or horizontal scrolling */
155 #define Is_Scroll_Field(field) \
156 (((field)->drows > (field)->rows) || \
157 ((field)->dcols > (field)->cols))
159 /* Logic to decide whether or not a field needs to have an individual window
160 instead of a derived window because it contains invisible parts.
161 This is true for non-public fields and for scrollable fields. */
162 #define Has_Invisible_Parts(field) \
163 (!((field)->opts & O_PUBLIC) || \
164 Is_Scroll_Field(field))
166 /* Logic to decide whether or not a field needs justification */
167 #define Justification_Allowed(field) \
168 (((field)->just != NO_JUSTIFICATION) && \
169 (Single_Line_Field(field)) && \
170 (((field)->dcols == (field)->cols) && \
171 ((field)->opts & O_STATIC)) )
173 /* Logic to determine whether or not a dynamic field may still grow */
174 #define Growable(field) ((field)->status & _MAY_GROW)
176 /* Macro to set the attributes for a fields window */
177 #define Set_Field_Window_Attributes(field,win) \
178 ( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
179 wattrset((win),(field)->fore) )
181 /* Logic to decide whether or not a field really appears on the form */
182 #define Field_Really_Appears(field) \
184 (field->form->status & _POSTED) &&\
185 (field->opts & O_VISIBLE) &&\
186 (field->page == field->form->curpage))
188 /* Logic to determine whether or not we are on the first position in the
190 #define First_Position_In_Current_Field(form) \
191 (((form)->currow==0) && ((form)->curcol==0))
194 #define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
195 #define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
197 /*---------------------------------------------------------------------------
198 | Facility : libnform
199 | Function : static char *Get_Start_Of_Data(char * buf, int blen)
201 | Description : Return pointer to first non-blank position in buffer.
202 | If buffer is empty return pointer to buffer itself.
204 | Return Values : Pointer to first non-blank position in buffer
205 +--------------------------------------------------------------------------*/
206 INLINE static char *Get_Start_Of_Data(char * buf, int blen)
209 char *end = &buf[blen];
211 assert(buf && blen>=0);
212 while( (p < end) && is_blank(*p) )
214 return( (p==end) ? buf : p );
217 /*---------------------------------------------------------------------------
218 | Facility : libnform
219 | Function : static char *After_End_Of_Data(char * buf, int blen)
221 | Description : Return pointer after last non-blank position in buffer.
222 | If buffer is empty, return pointer to buffer itself.
224 | Return Values : Pointer to position after last non-blank position in
226 +--------------------------------------------------------------------------*/
227 INLINE static char *After_End_Of_Data(char * buf,int blen)
229 char *p = &buf[blen];
231 assert(buf && blen>=0);
232 while( (p>buf) && is_blank(p[-1]) )
237 /*---------------------------------------------------------------------------
238 | Facility : libnform
239 | Function : static char *Get_First_Whitespace_Character(
240 | char * buf, int blen)
242 | Description : Position to the first whitespace character.
244 | Return Values : Pointer to first whitespace character in buffer.
245 +--------------------------------------------------------------------------*/
246 INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
249 char *end = &p[blen];
251 assert(buf && blen>=0);
252 while( (p < end) && !is_blank(*p))
254 return( (p==end) ? buf : p );
257 /*---------------------------------------------------------------------------
258 | Facility : libnform
259 | Function : static char *After_Last_Whitespace_Character(
260 | char * buf, int blen)
262 | Description : Get the position after the last whitespace character.
264 | Return Values : Pointer to position after last whitespace character in
266 +--------------------------------------------------------------------------*/
267 INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
269 char *p = &buf[blen];
271 assert(buf && blen>=0);
272 while( (p>buf) && !is_blank(p[-1]) )
277 /* Set this to 1 to use the div_t version. This is a good idea if your
278 compiler has an intrinsic div() support. Unfortunately GNU-C has it
280 N.B.: This only works if form->curcol follows immediately form->currow
281 and both are of type int.
283 #define USE_DIV_T (0)
285 /*---------------------------------------------------------------------------
286 | Facility : libnform
287 | Function : static void Adjust_Cursor_Position(
288 | FORM * form, const char * pos)
290 | Description : Set current row and column of the form to values
291 | corresponding to the buffer position.
294 +--------------------------------------------------------------------------*/
295 INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
300 field = form->current;
301 assert( pos >= field->buf && field->dcols > 0);
302 idx = (int)( pos - field->buf );
304 *((div_t *)&(form->currow)) = div(idx,field->dcols);
306 form->currow = idx / field->dcols;
307 form->curcol = idx - field->cols * form->currow;
309 if ( field->drows < form->currow )
313 /*---------------------------------------------------------------------------
314 | Facility : libnform
315 | Function : static void Buffer_To_Window(
316 | const FIELD * field,
319 | Description : Copy the buffer to the window. If its a multiline
320 | field, the buffer is split to the lines of the
321 | window without any editing.
324 +--------------------------------------------------------------------------*/
325 static void Buffer_To_Window(const FIELD * field, WINDOW * win)
332 assert(win && field);
334 width = getmaxx(win);
335 height = getmaxy(win);
337 for(row=0, pBuffer=field->buf;
339 row++, pBuffer += width )
341 if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
343 wmove( win, row, 0 );
344 waddnstr( win, pBuffer, len );
349 /*---------------------------------------------------------------------------
350 | Facility : libnform
351 | Function : static void Window_To_Buffer(
355 | Description : Copy the content of the window into the buffer.
356 | The multiple lines of a window are simply
357 | concatenated into the buffer. Pad characters in
358 | the window will be replaced by blanks in the buffer.
361 +--------------------------------------------------------------------------*/
362 static void Window_To_Buffer(WINDOW * win, FIELD * field)
369 assert(win && field && field->buf );
373 height = getmaxy(win);
375 for(row=0; (row < height) && (row < field->drows); row++ )
377 wmove( win, row, 0 );
378 len += winnstr( win, p+len, field->dcols );
382 /* replace visual padding character by blanks in buffer */
386 for(i=0; i<len; i++, p++)
394 /*---------------------------------------------------------------------------
395 | Facility : libnform
396 | Function : static void Synchronize_Buffer(FORM * form)
398 | Description : If there was a change, copy the content of the
399 | window into the buffer, so the buffer is synchronized
400 | with the windows content. We have to indicate that the
401 | buffer needs validation due to the change.
404 +--------------------------------------------------------------------------*/
405 INLINE static void Synchronize_Buffer(FORM * form)
407 if (form->status & _WINDOW_MODIFIED)
409 form->status &= ~_WINDOW_MODIFIED;
410 form->status |= _FCHECK_REQUIRED;
411 Window_To_Buffer(form->w,form->current);
412 wmove(form->w,form->currow,form->curcol);
416 /*---------------------------------------------------------------------------
417 | Facility : libnform
418 | Function : static bool Field_Grown( FIELD *field, int amount)
420 | Description : This function is called for growable dynamic fields
421 | only. It has to increase the buffers and to allocate
422 | a new window for this field.
423 | This function has the side effect to set a new
424 | field-buffer pointer, the dcols and drows values
425 | as well as a new current Window for the field.
427 | Return Values : TRUE - field successfully increased
428 | FALSE - there was some error
429 +--------------------------------------------------------------------------*/
430 static bool Field_Grown(FIELD * field, int amount)
434 if (field && Growable(field))
436 bool single_line_field = Single_Line_Field(field);
437 int old_buflen = Buffer_Length(field);
439 int old_dcols = field->dcols;
440 int old_drows = field->drows;
441 char *oldbuf = field->buf;
445 FORM *form = field->form;
446 bool need_visual_update = ((form != (FORM *)0) &&
447 (form->status & _POSTED) &&
448 (form->current==field));
450 if (need_visual_update)
451 Synchronize_Buffer(form);
453 if (single_line_field)
455 growth = field->cols * amount;
457 growth = Minimum(field->maxgrow - field->dcols,growth);
458 field->dcols += growth;
459 if (field->dcols == field->maxgrow)
460 field->status &= ~_MAY_GROW;
464 growth = (field->rows + field->nrow) * amount;
466 growth = Minimum(field->maxgrow - field->drows,growth);
467 field->drows += growth;
468 if (field->drows == field->maxgrow)
469 field->status &= ~_MAY_GROW;
471 /* drows, dcols changed, so we get really the new buffer length */
472 new_buflen = Buffer_Length(field);
473 newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
475 { /* restore to previous state */
476 field->dcols = old_dcols;
477 field->drows = old_drows;
478 if (( single_line_field && (field->dcols!=field->maxgrow)) ||
479 (!single_line_field && (field->drows!=field->maxgrow)))
480 field->status |= _MAY_GROW;
484 { /* Copy all the buffers. This is the reason why we can't
492 for(i=0;i<=field->nbuf;i++)
494 new_bp = Address_Of_Nth_Buffer(field,i);
495 old_bp = oldbuf + i*(1+old_buflen);
496 memcpy(new_bp,old_bp,(size_t)old_buflen);
497 if (new_buflen > old_buflen)
498 memset(new_bp + old_buflen,C_BLANK,
499 (size_t)(new_buflen - old_buflen));
500 *(new_bp + new_buflen) = '\0';
503 if (need_visual_update)
505 WINDOW *new_window = newpad(field->drows,field->dcols);
507 { /* restore old state */
508 field->dcols = old_dcols;
509 field->drows = old_drows;
511 if (( single_line_field &&
512 (field->dcols!=field->maxgrow)) ||
513 (!single_line_field &&
514 (field->drows!=field->maxgrow)))
515 field->status |= _MAY_GROW;
519 assert(form!=(FORM *)0);
522 form->w = new_window;
523 Set_Field_Window_Attributes(field,form->w);
525 Buffer_To_Window(field,form->w);
527 wmove(form->w,form->currow,form->curcol);
531 /* reflect changes in linked fields */
532 if (field != field->link)
535 for(linked_field = field->link;
536 linked_field!= field;
537 linked_field = linked_field->link)
539 linked_field->buf = field->buf;
540 linked_field->drows = field->drows;
541 linked_field->dcols = field->dcols;
550 /*---------------------------------------------------------------------------
551 | Facility : libnform
552 | Function : int _nc_Position_Form_Cursor(FORM * form)
554 | Description : Position the cursor in the window for the current
555 | field to be in sync. with the currow and curcol
558 | Return Values : E_OK - success
559 | E_BAD_ARGUMENT - invalid form pointer
560 | E_SYSTEM_ERROR - form has no current field or
562 +--------------------------------------------------------------------------*/
564 _nc_Position_Form_Cursor (FORM * form)
570 return(E_BAD_ARGUMENT);
572 if (!form->w || !form->current)
573 return(E_SYSTEM_ERROR);
575 field = form->current;
576 formwin = Get_Form_Window(form);
578 wmove( form->w, form->currow, form->curcol );
579 if ( Has_Invisible_Parts(field) )
581 /* in this case fieldwin isn't derived from formwin, so we have
582 to move the cursor in formwin by hand... */
584 field->frow + form->currow - form->toprow,
585 field->fcol + form->curcol - form->begincol);
593 /*---------------------------------------------------------------------------
594 | Facility : libnform
595 | Function : int _nc_Refresh_Current_Field(FORM * form)
597 | Description : Propagate the changes in the fields window to the
598 | window of the form.
600 | Return Values : E_OK - on success
601 | E_BAD_ARGUMENT - invalid form pointer
602 | E_SYSTEM_ERROR - general error
603 +--------------------------------------------------------------------------*/
605 _nc_Refresh_Current_Field (FORM * form)
611 RETURN(E_BAD_ARGUMENT);
613 if (!form->w || !form->current)
614 RETURN(E_SYSTEM_ERROR);
616 field = form->current;
617 formwin = Get_Form_Window(form);
619 if (field->opts & O_PUBLIC)
621 if (Is_Scroll_Field(field))
623 /* Again, in this case the fieldwin isn't derived from formwin,
624 so we have to perform a copy operation. */
625 if (Single_Line_Field(field))
626 { /* horizontal scrolling */
627 if (form->curcol < form->begincol)
628 form->begincol = form->curcol;
631 if (form->curcol >= (form->begincol + field->cols))
632 form->begincol = form->curcol - field->cols + 1;
641 field->cols + field->fcol - 1,
645 { /* A multiline, i.e. vertical scrolling field */
646 int row_after_bottom,first_modified_row,first_unmodified_row;
648 if (field->drows > field->rows)
650 row_after_bottom = form->toprow + field->rows;
651 if (form->currow < form->toprow)
653 form->toprow = form->currow;
654 field->status |= _NEWTOP;
656 if (form->currow >= row_after_bottom)
658 form->toprow = form->currow - field->rows + 1;
659 field->status |= _NEWTOP;
661 if (field->status & _NEWTOP)
662 { /* means we have to copy whole range */
663 first_modified_row = form->toprow;
664 first_unmodified_row = first_modified_row + field->rows;
665 field->status &= ~_NEWTOP;
668 { /* we try to optimize : finding the range of touched
670 first_modified_row = form->toprow;
671 while(first_modified_row < row_after_bottom)
673 if (is_linetouched(form->w,first_modified_row))
675 first_modified_row++;
677 first_unmodified_row = first_modified_row;
678 while(first_unmodified_row < row_after_bottom)
680 if (!is_linetouched(form->w,first_unmodified_row))
682 first_unmodified_row++;
688 first_modified_row = form->toprow;
689 first_unmodified_row = first_modified_row + field->rows;
691 if (first_unmodified_row != first_modified_row)
696 field->frow + first_modified_row - form->toprow,
698 field->frow + first_unmodified_row - form->toprow - 1,
699 field->cols + field->fcol - 1,
705 { /* if the field-window is simply a derived window, i.e. contains
706 no invisible parts, the whole thing is trivial
712 return _nc_Position_Form_Cursor(form);
715 /*---------------------------------------------------------------------------
716 | Facility : libnform
717 | Function : static void Perform_Justification(
721 | Description : Output field with requested justification
724 +--------------------------------------------------------------------------*/
725 static void Perform_Justification(FIELD * field, WINDOW * win)
731 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
732 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
736 assert(win && (field->drows == 1) && (field->dcols == field->cols));
743 col = (field->cols - len)/2;
746 col = field->cols - len;
753 waddnstr(win,bp,len);
757 /*---------------------------------------------------------------------------
758 | Facility : libnform
759 | Function : static void Undo_Justification(
763 | Description : Display field without any justification, i.e.
767 +--------------------------------------------------------------------------*/
768 static void Undo_Justification(FIELD * field, WINDOW * win)
773 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
774 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
780 waddnstr(win,bp,len);
784 /*---------------------------------------------------------------------------
785 | Facility : libnform
786 | Function : static bool Check_Char(
789 | TypeArgument *argp)
791 | Description : Perform a single character check for character ch
792 | according to the fieldtype instance.
794 | Return Values : TRUE - Character is valid
795 | FALSE - Character is invalid
796 +--------------------------------------------------------------------------*/
797 static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
801 if (typ->status & _LINKED_TYPE)
805 Check_Char(typ->left ,ch,argp->left ) ||
806 Check_Char(typ->right,ch,argp->right) );
811 return typ->ccheck(ch,(void *)argp);
814 return (isprint((unsigned char)ch) ? TRUE : FALSE);
817 /*---------------------------------------------------------------------------
818 | Facility : libnform
819 | Function : static int Display_Or_Erase_Field(
823 | Description : Create a subwindow for the field and display the
824 | buffer contents (apply justification if required)
825 | or simply erase the field.
827 | Return Values : E_OK - on success
828 | E_SYSTEM_ERROR - some error (typical no memory)
829 +--------------------------------------------------------------------------*/
830 static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
836 return E_SYSTEM_ERROR;
838 fwin = Get_Form_Window(field->form);
840 field->rows,field->cols,field->frow,field->fcol);
843 return E_SYSTEM_ERROR;
846 if (field->opts & O_VISIBLE)
847 Set_Field_Window_Attributes(field,win);
849 wattrset(win,getattrs(fwin));
855 if (field->opts & O_PUBLIC)
857 if (Justification_Allowed(field))
858 Perform_Justification(field,win);
860 Buffer_To_Window(field,win);
862 field->status &= ~_NEWTOP;
869 /* Macros to preset the bEraseFlag */
870 #define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
871 #define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
873 /*---------------------------------------------------------------------------
874 | Facility : libnform
875 | Function : static int Synchronize_Field(FIELD * field)
877 | Description : Synchronize the windows content with the value in
880 | Return Values : E_OK - success
881 | E_BAD_ARGUMENT - invalid field pointer
882 | E_SYSTEM_ERROR - some severe basic error
883 +--------------------------------------------------------------------------*/
884 static int Synchronize_Field(FIELD * field)
890 return(E_BAD_ARGUMENT);
892 if (((form=field->form) != (FORM *)0)
893 && Field_Really_Appears(field))
895 if (field == form->current)
897 form->currow = form->curcol = form->toprow = form->begincol = 0;
900 if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
901 Undo_Justification( field, form->w );
903 Buffer_To_Window( field, form->w );
905 field->status |= _NEWTOP;
906 res = _nc_Refresh_Current_Field( form );
909 res = Display_Field( field );
911 field->status |= _CHANGED;
915 /*---------------------------------------------------------------------------
916 | Facility : libnform
917 | Function : static int Synchronize_Linked_Fields(FIELD * field)
919 | Description : Propagate the Synchronize_Field function to all linked
920 | fields. The first error that occurs in the sequence
921 | of updates is the returnvalue.
923 | Return Values : E_OK - success
924 | E_BAD_ARGUMENT - invalid field pointer
925 | E_SYSTEM_ERROR - some severe basic error
926 +--------------------------------------------------------------------------*/
927 static int Synchronize_Linked_Fields(FIELD * field)
934 return(E_BAD_ARGUMENT);
937 return(E_SYSTEM_ERROR);
939 for(linked_field = field->link;
940 linked_field!= field;
941 linked_field = linked_field->link )
943 if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
950 /*---------------------------------------------------------------------------
951 | Facility : libnform
952 | Function : int _nc_Synchronize_Attributes(FIELD * field)
954 | Description : If a fields visual attributes have changed, this
955 | routine is called to propagate those changes to the
958 | Return Values : E_OK - success
959 | E_BAD_ARGUMENT - invalid field pointer
960 | E_SYSTEM_ERROR - some severe basic error
961 +--------------------------------------------------------------------------*/
963 _nc_Synchronize_Attributes (FIELD * field)
970 return(E_BAD_ARGUMENT);
972 if (((form=field->form) != (FORM *)0)
973 && Field_Really_Appears(field))
975 if (form->current==field)
977 Synchronize_Buffer(form);
978 Set_Field_Window_Attributes(field,form->w);
980 if (field->opts & O_PUBLIC)
982 if (Justification_Allowed(field))
983 Undo_Justification(field,form->w);
985 Buffer_To_Window(field,form->w);
989 formwin = Get_Form_Window(form);
990 copywin(form->w,formwin,
992 field->frow,field->fcol,
993 field->rows-1,field->cols-1,0);
995 Buffer_To_Window(field,form->w);
996 field->status |= _NEWTOP; /* fake refresh to paint all */
997 _nc_Refresh_Current_Field(form);
1002 res = Display_Field(field);
1008 /*---------------------------------------------------------------------------
1009 | Facility : libnform
1010 | Function : int _nc_Synchronize_Options(FIELD * field,
1011 | Field_Options newopts)
1013 | Description : If a fields options have changed, this routine is
1014 | called to propagate these changes to the screen and
1015 | to really change the behaviour of the field.
1017 | Return Values : E_OK - success
1018 | E_BAD_ARGUMENT - invalid field pointer
1019 | E_SYSTEM_ERROR - some severe basic error
1020 +--------------------------------------------------------------------------*/
1022 _nc_Synchronize_Options
1023 (FIELD *field, Field_Options newopts)
1025 Field_Options oldopts;
1026 Field_Options changed_opts;
1031 return(E_BAD_ARGUMENT);
1033 oldopts = field->opts;
1034 changed_opts = oldopts ^ newopts;
1035 field->opts = newopts;
1040 if (form->current == field)
1042 field->opts = oldopts;
1046 if (form->status & _POSTED)
1048 if ((form->curpage == field->page))
1050 if (changed_opts & O_VISIBLE)
1052 if (newopts & O_VISIBLE)
1053 res = Display_Field(field);
1055 res = Erase_Field(field);
1059 if ((changed_opts & O_PUBLIC) &&
1060 (newopts & O_VISIBLE))
1061 res = Display_Field(field);
1067 if (changed_opts & O_STATIC)
1069 bool single_line_field = Single_Line_Field(field);
1072 if (newopts & O_STATIC)
1073 { /* the field becomes now static */
1074 field->status &= ~_MAY_GROW;
1075 /* if actually we have no hidden columns, justification may
1077 if (single_line_field &&
1078 (field->cols == field->dcols) &&
1079 (field->just != NO_JUSTIFICATION) &&
1080 Field_Really_Appears(field))
1082 res2 = Display_Field(field);
1086 { /* field is no longer static */
1087 if ((field->maxgrow==0) ||
1088 ( single_line_field && (field->dcols < field->maxgrow)) ||
1089 (!single_line_field && (field->drows < field->maxgrow)))
1091 field->status |= _MAY_GROW;
1092 /* a field with justification now changes its behaviour,
1093 so we must redisplay it */
1094 if (single_line_field &&
1095 (field->just != NO_JUSTIFICATION) &&
1096 Field_Really_Appears(field))
1098 res2 = Display_Field(field);
1109 /*---------------------------------------------------------------------------
1110 | Facility : libnform
1111 | Function : int _nc_Set_Current_Field(FORM * form,
1114 | Description : Make the newfield the new current field.
1116 | Return Values : E_OK - success
1117 | E_BAD_ARGUMENT - invalid form or field pointer
1118 | E_SYSTEM_ERROR - some severe basic error
1119 +--------------------------------------------------------------------------*/
1121 _nc_Set_Current_Field
1122 (FORM *form, FIELD *newfield)
1127 if (!form || !newfield || !form->current || (newfield->form!=form))
1128 return(E_BAD_ARGUMENT);
1130 if ( (form->status & _IN_DRIVER) )
1131 return(E_BAD_STATE);
1134 return(E_NOT_CONNECTED);
1136 field = form->current;
1138 if ((field!=newfield) ||
1139 !(form->status & _POSTED))
1142 (field->opts & O_VISIBLE) &&
1143 (field->form->curpage == field->page))
1145 _nc_Refresh_Current_Field(form);
1146 if (field->opts & O_PUBLIC)
1148 if (field->drows > field->rows)
1150 if (form->toprow==0)
1151 field->status &= ~_NEWTOP;
1153 field->status |= _NEWTOP;
1157 if (Justification_Allowed(field))
1159 Window_To_Buffer(form->w,field);
1161 Perform_Justification(field,form->w);
1167 form->w = (WINDOW *)0;
1172 if (Has_Invisible_Parts(field))
1173 new_window = newpad(field->drows,field->dcols);
1175 new_window = derwin(Get_Form_Window(form),
1176 field->rows,field->cols,field->frow,field->fcol);
1179 return(E_SYSTEM_ERROR);
1181 form->current = field;
1185 form->w = new_window;
1187 form->status &= ~_WINDOW_MODIFIED;
1188 Set_Field_Window_Attributes(field,form->w);
1190 if (Has_Invisible_Parts(field))
1193 Buffer_To_Window(field,form->w);
1197 if (Justification_Allowed(field))
1200 Undo_Justification(field,form->w);
1205 untouchwin(form->w);
1208 form->currow = form->curcol = form->toprow = form->begincol = 0;
1212 /*----------------------------------------------------------------------------
1213 Intra-Field Navigation routines
1214 --------------------------------------------------------------------------*/
1216 /*---------------------------------------------------------------------------
1217 | Facility : libnform
1218 | Function : static int IFN_Next_Character(FORM * form)
1220 | Description : Move to the next character in the field. In a multiline
1221 | field this wraps at the end of the line.
1223 | Return Values : E_OK - success
1224 | E_REQUEST_DENIED - at the rightmost position
1225 +--------------------------------------------------------------------------*/
1226 static int IFN_Next_Character(FORM * form)
1228 FIELD *field = form->current;
1230 if ((++(form->curcol))==field->dcols)
1232 if ((++(form->currow))==field->drows)
1234 #if GROW_IF_NAVIGATE
1235 if (!Single_Line_Field(field) && Field_Grown(field,1)) {
1241 #if GROW_IF_NAVIGATE
1242 if (Single_Line_Field(field) && Field_Grown(field,1))
1246 return(E_REQUEST_DENIED);
1253 /*---------------------------------------------------------------------------
1254 | Facility : libnform
1255 | Function : static int IFN_Previous_Character(FORM * form)
1257 | Description : Move to the previous character in the field. In a
1258 | multiline field this wraps and the beginning of the
1261 | Return Values : E_OK - success
1262 | E_REQUEST_DENIED - at the leftmost position
1263 +--------------------------------------------------------------------------*/
1264 static int IFN_Previous_Character(FORM * form)
1266 if ((--(form->curcol))<0)
1268 if ((--(form->currow))<0)
1272 return(E_REQUEST_DENIED);
1274 form->curcol = form->current->dcols - 1;
1279 /*---------------------------------------------------------------------------
1280 | Facility : libnform
1281 | Function : static int IFN_Next_Line(FORM * form)
1283 | Description : Move to the beginning of the next line in the field
1285 | Return Values : E_OK - success
1286 | E_REQUEST_DENIED - at the last line
1287 +--------------------------------------------------------------------------*/
1288 static int IFN_Next_Line(FORM * form)
1290 FIELD *field = form->current;
1292 if ((++(form->currow))==field->drows)
1294 #if GROW_IF_NAVIGATE
1295 if (!Single_Line_Field(field) && Field_Grown(field,1))
1299 return(E_REQUEST_DENIED);
1305 /*---------------------------------------------------------------------------
1306 | Facility : libnform
1307 | Function : static int IFN_Previous_Line(FORM * form)
1309 | Description : Move to the beginning of the previous line in the field
1311 | Return Values : E_OK - success
1312 | E_REQUEST_DENIED - at the first line
1313 +--------------------------------------------------------------------------*/
1314 static int IFN_Previous_Line(FORM * form)
1316 if ( (--(form->currow)) < 0 )
1319 return(E_REQUEST_DENIED);
1325 /*---------------------------------------------------------------------------
1326 | Facility : libnform
1327 | Function : static int IFN_Next_Word(FORM * form)
1329 | Description : Move to the beginning of the next word in the field.
1331 | Return Values : E_OK - success
1332 | E_REQUEST_DENIED - there is no next word
1333 +--------------------------------------------------------------------------*/
1334 static int IFN_Next_Word(FORM * form)
1336 FIELD *field = form->current;
1337 char *bp = Address_Of_Current_Position_In_Buffer(form);
1341 /* We really need access to the data, so we have to synchronize */
1342 Synchronize_Buffer(form);
1344 /* Go to the first whitespace after the current position (including
1345 current position). This is then the startpoint to look for the
1346 next non-blank data */
1347 s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
1348 (int)(bp - field->buf));
1350 /* Find the start of the next word */
1351 t = Get_Start_Of_Data(s,Buffer_Length(field) -
1352 (int)(s - field->buf));
1353 #if !FRIENDLY_PREV_NEXT_WORD
1355 return(E_REQUEST_DENIED);
1359 Adjust_Cursor_Position(form,t);
1364 /*---------------------------------------------------------------------------
1365 | Facility : libnform
1366 | Function : static int IFN_Previous_Word(FORM * form)
1368 | Description : Move to the beginning of the previous word in the field.
1370 | Return Values : E_OK - success
1371 | E_REQUEST_DENIED - there is no previous word
1372 +--------------------------------------------------------------------------*/
1373 static int IFN_Previous_Word(FORM * form)
1375 FIELD *field = form->current;
1376 char *bp = Address_Of_Current_Position_In_Buffer(form);
1381 /* We really need access to the data, so we have to synchronize */
1382 Synchronize_Buffer(form);
1384 s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
1385 /* s points now right after the last non-blank in the buffer before bp.
1386 If bp was in a word, s equals bp. In this case we must find the last
1387 whitespace in the buffer before bp and repeat the game to really find
1388 the previous word! */
1392 /* And next call now goes backward to look for the last whitespace
1393 before that, pointing right after this, so it points to the begin
1394 of the previous word.
1396 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1397 #if !FRIENDLY_PREV_NEXT_WORD
1399 return(E_REQUEST_DENIED);
1402 { /* and do it again, replacing bp by t */
1403 s = After_End_Of_Data(field->buf,(int)(t - field->buf));
1404 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1405 #if !FRIENDLY_PREV_NEXT_WORD
1407 return(E_REQUEST_DENIED);
1410 Adjust_Cursor_Position(form,t);
1414 /*---------------------------------------------------------------------------
1415 | Facility : libnform
1416 | Function : static int IFN_Beginning_Of_Field(FORM * form)
1418 | Description : Place the cursor at the first non-pad character in
1421 | Return Values : E_OK - success
1422 +--------------------------------------------------------------------------*/
1423 static int IFN_Beginning_Of_Field(FORM * form)
1425 FIELD *field = form->current;
1427 Synchronize_Buffer(form);
1428 Adjust_Cursor_Position(form,
1429 Get_Start_Of_Data(field->buf,Buffer_Length(field)));
1433 /*---------------------------------------------------------------------------
1434 | Facility : libnform
1435 | Function : static int IFN_End_Of_Field(FORM * form)
1437 | Description : Place the cursor after the last non-pad character in
1438 | the field. If the field occupies the last position in
1439 | the buffer, the cursos is positioned on the last
1442 | Return Values : E_OK - success
1443 +--------------------------------------------------------------------------*/
1444 static int IFN_End_Of_Field(FORM * form)
1446 FIELD *field = form->current;
1449 Synchronize_Buffer(form);
1450 pos = After_End_Of_Data(field->buf,Buffer_Length(field));
1451 if (pos==(field->buf + Buffer_Length(field)))
1453 Adjust_Cursor_Position(form,pos);
1457 /*---------------------------------------------------------------------------
1458 | Facility : libnform
1459 | Function : static int IFN_Beginning_Of_Line(FORM * form)
1461 | Description : Place the cursor on the first non-pad character in
1462 | the current line of the field.
1464 | Return Values : E_OK - success
1465 +--------------------------------------------------------------------------*/
1466 static int IFN_Beginning_Of_Line(FORM * form)
1468 FIELD *field = form->current;
1470 Synchronize_Buffer(form);
1471 Adjust_Cursor_Position(form,
1472 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1477 /*---------------------------------------------------------------------------
1478 | Facility : libnform
1479 | Function : static int IFN_End_Of_Line(FORM * form)
1481 | Description : Place the cursor after the last non-pad character in the
1482 | current line of the field. If the field occupies the
1483 | last column in the line, the cursor is positioned on the
1484 | last character of the line.
1486 | Return Values : E_OK - success
1487 +--------------------------------------------------------------------------*/
1488 static int IFN_End_Of_Line(FORM * form)
1490 FIELD *field = form->current;
1494 Synchronize_Buffer(form);
1495 bp = Address_Of_Current_Row_In_Buffer(form);
1496 pos = After_End_Of_Data(bp,field->dcols);
1497 if (pos == (bp + field->dcols))
1499 Adjust_Cursor_Position(form,pos);
1503 /*---------------------------------------------------------------------------
1504 | Facility : libnform
1505 | Function : static int IFN_Left_Character(FORM * form)
1507 | Description : Move one character to the left in the current line.
1508 | This doesn't cycle.
1510 | Return Values : E_OK - success
1511 | E_REQUEST_DENIED - already in first column
1512 +--------------------------------------------------------------------------*/
1513 static int IFN_Left_Character(FORM * form)
1515 if ( (--(form->curcol)) < 0 )
1518 return(E_REQUEST_DENIED);
1523 /*---------------------------------------------------------------------------
1524 | Facility : libnform
1525 | Function : static int IFN_Right_Character(FORM * form)
1527 | Description : Move one character to the right in the current line.
1528 | This doesn't cycle.
1530 | Return Values : E_OK - success
1531 | E_REQUEST_DENIED - already in last column
1532 +--------------------------------------------------------------------------*/
1533 static int IFN_Right_Character(FORM * form)
1535 if ( (++(form->curcol)) == form->current->dcols )
1537 #if GROW_IF_NAVIGATE
1538 FIELD *field = form->current;
1539 if (Single_Line_Field(field) && Field_Grown(field,1))
1543 return(E_REQUEST_DENIED);
1548 /*---------------------------------------------------------------------------
1549 | Facility : libnform
1550 | Function : static int IFN_Up_Character(FORM * form)
1552 | Description : Move one line up. This doesn't cycle through the lines
1555 | Return Values : E_OK - success
1556 | E_REQUEST_DENIED - already in last column
1557 +--------------------------------------------------------------------------*/
1558 static int IFN_Up_Character(FORM * form)
1560 if ( (--(form->currow)) < 0 )
1563 return(E_REQUEST_DENIED);
1568 /*---------------------------------------------------------------------------
1569 | Facility : libnform
1570 | Function : static int IFN_Down_Character(FORM * form)
1572 | Description : Move one line down. This doesn't cycle through the
1573 | lines of the field.
1575 | Return Values : E_OK - success
1576 | E_REQUEST_DENIED - already in last column
1577 +--------------------------------------------------------------------------*/
1578 static int IFN_Down_Character(FORM * form)
1580 FIELD *field = form->current;
1582 if ( (++(form->currow)) == field->drows )
1584 #if GROW_IF_NAVIGATE
1585 if (!Single_Line_Field(field) && Field_Grown(field,1))
1589 return(E_REQUEST_DENIED);
1593 /*----------------------------------------------------------------------------
1594 END of Intra-Field Navigation routines
1595 --------------------------------------------------------------------------*/
1597 /*----------------------------------------------------------------------------
1598 Vertical scrolling helper routines
1599 --------------------------------------------------------------------------*/
1601 /*---------------------------------------------------------------------------
1602 | Facility : libnform
1603 | Function : static int VSC_Generic(FORM *form, int lines)
1605 | Description : Scroll multi-line field forward (lines>0) or
1606 | backward (lines<0) this many lines.
1608 | Return Values : E_OK - success
1609 | E_REQUEST_DENIED - can't scroll
1610 +--------------------------------------------------------------------------*/
1611 static int VSC_Generic(FORM *form, int lines)
1613 FIELD *field = form->current;
1614 int res = E_REQUEST_DENIED;
1615 int rows_to_go = (lines > 0 ? lines : -lines);
1619 if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
1620 rows_to_go = (field->drows - field->rows - form->toprow);
1624 form->currow += rows_to_go;
1625 form->toprow += rows_to_go;
1631 if (rows_to_go > form->toprow)
1632 rows_to_go = form->toprow;
1636 form->currow -= rows_to_go;
1637 form->toprow -= rows_to_go;
1643 /*----------------------------------------------------------------------------
1644 End of Vertical scrolling helper routines
1645 --------------------------------------------------------------------------*/
1647 /*----------------------------------------------------------------------------
1648 Vertical scrolling routines
1649 --------------------------------------------------------------------------*/
1651 /*---------------------------------------------------------------------------
1652 | Facility : libnform
1653 | Function : static int Vertical_Scrolling(
1654 | int (* const fct) (FORM *),
1657 | Description : Performs the generic vertical scrolling routines.
1658 | This has to check for a multi-line field and to set
1659 | the _NEWTOP flag if scrolling really occured.
1661 | Return Values : Propagated error code from low-level driver calls
1662 +--------------------------------------------------------------------------*/
1663 static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
1665 int res = E_REQUEST_DENIED;
1667 if (!Single_Line_Field(form->current))
1671 form->current->status |= _NEWTOP;
1676 /*---------------------------------------------------------------------------
1677 | Facility : libnform
1678 | Function : static int VSC_Scroll_Line_Forward(FORM * form)
1680 | Description : Scroll multi-line field forward a line
1682 | Return Values : E_OK - success
1683 | E_REQUEST_DENIED - no data ahead
1684 +--------------------------------------------------------------------------*/
1685 static int VSC_Scroll_Line_Forward(FORM * form)
1687 return VSC_Generic(form,1);
1690 /*---------------------------------------------------------------------------
1691 | Facility : libnform
1692 | Function : static int VSC_Scroll_Line_Backward(FORM * form)
1694 | Description : Scroll multi-line field backward a line
1696 | Return Values : E_OK - success
1697 | E_REQUEST_DENIED - no data behind
1698 +--------------------------------------------------------------------------*/
1699 static int VSC_Scroll_Line_Backward(FORM * form)
1701 return VSC_Generic(form,-1);
1704 /*---------------------------------------------------------------------------
1705 | Facility : libnform
1706 | Function : static int VSC_Scroll_Page_Forward(FORM * form)
1708 | Description : Scroll a multi-line field forward a page
1710 | Return Values : E_OK - success
1711 | E_REQUEST_DENIED - no data ahead
1712 +--------------------------------------------------------------------------*/
1713 static int VSC_Scroll_Page_Forward(FORM * form)
1715 return VSC_Generic(form,form->current->rows);
1718 /*---------------------------------------------------------------------------
1719 | Facility : libnform
1720 | Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1722 | Description : Scroll a multi-line field forward half a page
1724 | Return Values : E_OK - success
1725 | E_REQUEST_DENIED - no data ahead
1726 +--------------------------------------------------------------------------*/
1727 static int VSC_Scroll_Half_Page_Forward(FORM * form)
1729 return VSC_Generic(form,(form->current->rows + 1)/2);
1732 /*---------------------------------------------------------------------------
1733 | Facility : libnform
1734 | Function : static int VSC_Scroll_Page_Backward(FORM * form)
1736 | Description : Scroll a multi-line field backward a page
1738 | Return Values : E_OK - success
1739 | E_REQUEST_DENIED - no data behind
1740 +--------------------------------------------------------------------------*/
1741 static int VSC_Scroll_Page_Backward(FORM * form)
1743 return VSC_Generic(form, -(form->current->rows));
1746 /*---------------------------------------------------------------------------
1747 | Facility : libnform
1748 | Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
1750 | Description : Scroll a multi-line field backward half a page
1752 | Return Values : E_OK - success
1753 | E_REQUEST_DENIED - no data behind
1754 +--------------------------------------------------------------------------*/
1755 static int VSC_Scroll_Half_Page_Backward(FORM * form)
1757 return VSC_Generic(form, -((form->current->rows + 1)/2));
1759 /*----------------------------------------------------------------------------
1760 End of Vertical scrolling routines
1761 --------------------------------------------------------------------------*/
1763 /*----------------------------------------------------------------------------
1764 Horizontal scrolling helper routines
1765 --------------------------------------------------------------------------*/
1767 /*---------------------------------------------------------------------------
1768 | Facility : libnform
1769 | Function : static int HSC_Generic(FORM *form, int columns)
1771 | Description : Scroll single-line field forward (columns>0) or
1772 | backward (columns<0) this many columns.
1774 | Return Values : E_OK - success
1775 | E_REQUEST_DENIED - can't scroll
1776 +--------------------------------------------------------------------------*/
1777 static int HSC_Generic(FORM *form, int columns)
1779 FIELD *field = form->current;
1780 int res = E_REQUEST_DENIED;
1781 int cols_to_go = (columns > 0 ? columns : -columns);
1785 if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
1786 cols_to_go = field->dcols - field->cols - form->begincol;
1790 form->curcol += cols_to_go;
1791 form->begincol += cols_to_go;
1797 if ( cols_to_go > form->begincol )
1798 cols_to_go = form->begincol;
1802 form->curcol -= cols_to_go;
1803 form->begincol -= cols_to_go;
1809 /*----------------------------------------------------------------------------
1810 End of Horizontal scrolling helper routines
1811 --------------------------------------------------------------------------*/
1813 /*----------------------------------------------------------------------------
1814 Horizontal scrolling routines
1815 --------------------------------------------------------------------------*/
1817 /*---------------------------------------------------------------------------
1818 | Facility : libnform
1819 | Function : static int Horizontal_Scrolling(
1820 | int (* const fct) (FORM *),
1823 | Description : Performs the generic horizontal scrolling routines.
1824 | This has to check for a single-line field.
1826 | Return Values : Propagated error code from low-level driver calls
1827 +--------------------------------------------------------------------------*/
1828 static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
1830 if (Single_Line_Field(form->current))
1833 return(E_REQUEST_DENIED);
1836 /*---------------------------------------------------------------------------
1837 | Facility : libnform
1838 | Function : static int HSC_Scroll_Char_Forward(FORM * form)
1840 | Description : Scroll single-line field forward a character
1842 | Return Values : E_OK - success
1843 | E_REQUEST_DENIED - no data ahead
1844 +--------------------------------------------------------------------------*/
1845 static int HSC_Scroll_Char_Forward(FORM *form)
1847 return HSC_Generic(form,1);
1850 /*---------------------------------------------------------------------------
1851 | Facility : libnform
1852 | Function : static int HSC_Scroll_Char_Backward(FORM * form)
1854 | Description : Scroll single-line field backward a character
1856 | Return Values : E_OK - success
1857 | E_REQUEST_DENIED - no data behind
1858 +--------------------------------------------------------------------------*/
1859 static int HSC_Scroll_Char_Backward(FORM *form)
1861 return HSC_Generic(form,-1);
1864 /*---------------------------------------------------------------------------
1865 | Facility : libnform
1866 | Function : static int HSC_Horizontal_Line_Forward(FORM* form)
1868 | Description : Scroll single-line field forward a line
1870 | Return Values : E_OK - success
1871 | E_REQUEST_DENIED - no data ahead
1872 +--------------------------------------------------------------------------*/
1873 static int HSC_Horizontal_Line_Forward(FORM * form)
1875 return HSC_Generic(form,form->current->cols);
1878 /*---------------------------------------------------------------------------
1879 | Facility : libnform
1880 | Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
1882 | Description : Scroll single-line field forward half a line
1884 | Return Values : E_OK - success
1885 | E_REQUEST_DENIED - no data ahead
1886 +--------------------------------------------------------------------------*/
1887 static int HSC_Horizontal_Half_Line_Forward(FORM * form)
1889 return HSC_Generic(form,(form->current->cols + 1)/2);
1892 /*---------------------------------------------------------------------------
1893 | Facility : libnform
1894 | Function : static int HSC_Horizontal_Line_Backward(FORM* form)
1896 | Description : Scroll single-line field backward a line
1898 | Return Values : E_OK - success
1899 | E_REQUEST_DENIED - no data behind
1900 +--------------------------------------------------------------------------*/
1901 static int HSC_Horizontal_Line_Backward(FORM * form)
1903 return HSC_Generic(form,-(form->current->cols));
1906 /*---------------------------------------------------------------------------
1907 | Facility : libnform
1908 | Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
1910 | Description : Scroll single-line field backward half a line
1912 | Return Values : E_OK - success
1913 | E_REQUEST_DENIED - no data behind
1914 +--------------------------------------------------------------------------*/
1915 static int HSC_Horizontal_Half_Line_Backward(FORM * form)
1917 return HSC_Generic(form,-((form->current->cols + 1)/2));
1920 /*----------------------------------------------------------------------------
1921 End of Horizontal scrolling routines
1922 --------------------------------------------------------------------------*/
1924 /*----------------------------------------------------------------------------
1925 Helper routines for Field Editing
1926 --------------------------------------------------------------------------*/
1928 /*---------------------------------------------------------------------------
1929 | Facility : libnform
1930 | Function : static bool Is_There_Room_For_A_Line(FORM * form)
1932 | Description : Check whether or not there is enough room in the
1933 | buffer to enter a whole line.
1935 | Return Values : TRUE - there is enough space
1936 | FALSE - there is not enough space
1937 +--------------------------------------------------------------------------*/
1938 INLINE static bool Is_There_Room_For_A_Line(FORM * form)
1940 FIELD *field = form->current;
1941 char *begin_of_last_line, *s;
1943 Synchronize_Buffer(form);
1944 begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
1945 s = After_End_Of_Data(begin_of_last_line,field->dcols);
1946 return ((s==begin_of_last_line) ? TRUE : FALSE);
1949 /*---------------------------------------------------------------------------
1950 | Facility : libnform
1951 | Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1953 | Description : Checks whether or not there is room for a new character
1954 | in the current line.
1956 | Return Values : TRUE - there is room
1957 | FALSE - there is not enough room (line full)
1958 +--------------------------------------------------------------------------*/
1959 INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1961 int last_char_in_line;
1963 wmove(form->w,form->currow,form->current->dcols-1);
1964 last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
1965 wmove(form->w,form->currow,form->curcol);
1966 return (((last_char_in_line == form->current->pad) ||
1967 is_blank(last_char_in_line)) ? TRUE : FALSE);
1970 #define There_Is_No_Room_For_A_Char_In_Line(f) \
1971 !Is_There_Room_For_A_Char_In_Line(f)
1973 /*---------------------------------------------------------------------------
1974 | Facility : libnform
1975 | Function : static int Insert_String(
1981 | Description : Insert the 'len' characters beginning at pointer 'txt'
1982 | into the 'row' of the 'form'. The insertion occurs
1983 | on the beginning of the row, all other characters are
1984 | moved to the right. After the text a pad character will
1985 | be inserted to separate the text from the rest. If
1986 | necessary the insertion moves characters on the next
1987 | line to make place for the requested insertion string.
1989 | Return Values : E_OK - success
1990 | E_REQUEST_DENIED -
1991 | E_SYSTEM_ERROR - system error
1992 +--------------------------------------------------------------------------*/
1993 static int Insert_String(FORM *form, int row, char *txt, int len)
1995 FIELD *field = form->current;
1996 char *bp = Address_Of_Row_In_Buffer(field,row);
1997 int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
1998 int freelen = field->dcols - datalen;
1999 int requiredlen = len+1;
2001 int result = E_REQUEST_DENIED;
2002 const char *Space = " ";
2004 if (freelen >= requiredlen)
2006 wmove(form->w,row,0);
2007 winsnstr(form->w,txt,len);
2008 wmove(form->w,row,len);
2009 winsnstr(form->w,Space,1);
2013 { /* we have to move characters on the next line. If we are on the
2014 last line this may work, if the field is growable */
2015 if ((row == (field->drows - 1)) && Growable(field))
2017 if (!Field_Grown(field,1))
2018 return(E_SYSTEM_ERROR);
2019 /* !!!Side-Effect : might be changed due to growth!!! */
2020 bp = Address_Of_Row_In_Buffer(field,row);
2023 if (row < (field->drows - 1))
2025 split = After_Last_Whitespace_Character(bp,
2026 (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
2027 requiredlen) - bp));
2028 /* split points now to the first character of the portion of the
2029 line that must be moved to the next line */
2030 datalen = (int)(split-bp); /* + freelen has to stay on this line */
2031 freelen = field->dcols - (datalen + freelen); /* for the next line */
2033 if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
2035 wmove(form->w,row,datalen);
2037 wmove(form->w,row,0);
2038 winsnstr(form->w,txt,len);
2039 wmove(form->w,row,len);
2040 winsnstr(form->w,Space,1);
2048 /*---------------------------------------------------------------------------
2049 | Facility : libnform
2050 | Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2053 | Description : If a character has been entered into a field, it may
2054 | be that wrapping has to occur. This routine checks
2055 | whether or not wrapping is required and if so, performs
2058 | Return Values : E_OK - no wrapping required or wrapping
2060 | E_REQUEST_DENIED -
2061 | E_SYSTEM_ERROR - some system error
2062 +--------------------------------------------------------------------------*/
2063 static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
2065 FIELD *field = form->current;
2066 int result = E_REQUEST_DENIED;
2067 bool Last_Row = ((field->drows - 1) == form->currow);
2069 if ( (field->opts & O_WRAP) && /* wrapping wanted */
2070 (!Single_Line_Field(field)) && /* must be multi-line */
2071 (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
2072 (!Last_Row || Growable(field)) ) /* there are more lines*/
2076 int chars_to_be_wrapped;
2077 int chars_to_remain_on_line;
2079 { /* the above logic already ensures, that in this case the field
2081 if (!Field_Grown(field,1))
2082 return E_SYSTEM_ERROR;
2084 bp = Address_Of_Current_Row_In_Buffer(form);
2085 Window_To_Buffer(form->w,field);
2086 split = After_Last_Whitespace_Character(bp,field->dcols);
2087 /* split points to the first character of the sequence to be brought
2089 chars_to_remain_on_line = (int)(split - bp);
2090 chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2091 if (chars_to_remain_on_line > 0)
2093 if ((result=Insert_String(form,form->currow+1,split,
2094 chars_to_be_wrapped)) == E_OK)
2096 wmove(form->w,form->currow,chars_to_remain_on_line);
2098 if (form->curcol >= chars_to_remain_on_line)
2101 form->curcol -= chars_to_remain_on_line;
2110 wmove(form->w,form->currow,form->curcol);
2112 Window_To_Buffer(form->w,field);
2113 result = E_REQUEST_DENIED;
2117 result = E_OK; /* wrapping was not necessary */
2121 /*----------------------------------------------------------------------------
2122 Field Editing routines
2123 --------------------------------------------------------------------------*/
2125 /*---------------------------------------------------------------------------
2126 | Facility : libnform
2127 | Function : static int Field_Editing(
2128 | int (* const fct) (FORM *),
2131 | Description : Generic routine for field editing requests. The driver
2132 | routines are only called for editable fields, the
2133 | _WINDOW_MODIFIED flag is set if editing occured.
2134 | This is somewhat special due to the overload semantics
2135 | of the NEW_LINE and DEL_PREV requests.
2137 | Return Values : Error code from low level drivers.
2138 +--------------------------------------------------------------------------*/
2139 static int Field_Editing(int (* const fct) (FORM *), FORM * form)
2141 int res = E_REQUEST_DENIED;
2143 /* We have to deal here with the specific case of the overloaded
2144 behaviour of New_Line and Delete_Previous requests.
2145 They may end up in navigational requests if we are on the first
2146 character in a field. But navigation is also allowed on non-
2149 if ((fct==FE_Delete_Previous) &&
2150 (form->opts & O_BS_OVERLOAD) &&
2151 First_Position_In_Current_Field(form) )
2153 res = Inter_Field_Navigation(FN_Previous_Field,form);
2157 if (fct==FE_New_Line)
2159 if ((form->opts & O_NL_OVERLOAD) &&
2160 First_Position_In_Current_Field(form))
2162 res = Inter_Field_Navigation(FN_Next_Field,form);
2165 /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2170 /* From now on, everything must be editable */
2171 if (form->current->opts & O_EDIT)
2175 form->status |= _WINDOW_MODIFIED;
2182 /*---------------------------------------------------------------------------
2183 | Facility : libnform
2184 | Function : static int FE_New_Line(FORM * form)
2186 | Description : Perform a new line request. This is rather complex
2187 | compared to other routines in this code due to the
2188 | rather difficult to understand description in the
2191 | Return Values : E_OK - success
2192 | E_REQUEST_DENIED - new line not allowed
2193 | E_SYSTEM_ERROR - system error
2194 +--------------------------------------------------------------------------*/
2195 static int FE_New_Line(FORM * form)
2197 FIELD *field = form->current;
2199 bool Last_Row = ((field->drows - 1)==form->currow);
2201 if (form->status & _OVLMODE)
2204 (!(Growable(field) && !Single_Line_Field(field))))
2206 if (!(form->opts & O_NL_OVERLOAD))
2207 return(E_REQUEST_DENIED);
2209 /* we have to set this here, although it is also
2210 handled in the generic routine. The reason is,
2211 that FN_Next_Field may fail, but the form is
2212 definitively changed */
2213 form->status |= _WINDOW_MODIFIED;
2214 return Inter_Field_Navigation(FN_Next_Field,form);
2218 if (Last_Row && !Field_Grown(field,1))
2219 { /* N.B.: due to the logic in the 'if', LastRow==TRUE
2220 means here that the field is growable and not
2221 a single-line field */
2222 return(E_SYSTEM_ERROR);
2227 form->status |= _WINDOW_MODIFIED;
2234 !(Growable(field) && !Single_Line_Field(field)))
2236 if (!(form->opts & O_NL_OVERLOAD))
2237 return(E_REQUEST_DENIED);
2238 return Inter_Field_Navigation(FN_Next_Field,form);
2242 bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2244 if (!(May_Do_It || Growable(field)))
2245 return(E_REQUEST_DENIED);
2246 if (!May_Do_It && !Field_Grown(field,1))
2247 return(E_SYSTEM_ERROR);
2249 bp= Address_Of_Current_Position_In_Buffer(form);
2250 t = After_End_Of_Data(bp,field->dcols - form->curcol);
2254 wmove(form->w,form->currow,form->curcol);
2256 waddnstr(form->w,bp,(int)(t-bp));
2257 form->status |= _WINDOW_MODIFIED;
2263 /*---------------------------------------------------------------------------
2264 | Facility : libnform
2265 | Function : static int FE_Insert_Character(FORM * form)
2267 | Description : Insert blank character at the cursor position
2269 | Return Values : E_OK
2271 +--------------------------------------------------------------------------*/
2272 static int FE_Insert_Character(FORM * form)
2274 FIELD *field = form->current;
2275 int result = E_REQUEST_DENIED;
2277 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2279 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2281 if (There_Is_Room ||
2282 ((Single_Line_Field(field) && Growable(field))))
2284 if (!There_Is_Room && !Field_Grown(field,1))
2285 result = E_SYSTEM_ERROR;
2288 winsch(form->w,(chtype)C_BLANK);
2289 result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2296 /*---------------------------------------------------------------------------
2297 | Facility : libnform
2298 | Function : static int FE_Insert_Line(FORM * form)
2300 | Description : Insert a blank line at the cursor position
2302 | Return Values : E_OK - success
2303 | E_REQUEST_DENIED - line can not be inserted
2304 +--------------------------------------------------------------------------*/
2305 static int FE_Insert_Line(FORM * form)
2307 FIELD *field = form->current;
2308 int result = E_REQUEST_DENIED;
2310 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2312 bool Maybe_Done = (form->currow!=(field->drows-1)) &&
2313 Is_There_Room_For_A_Line(form);
2315 if (!Single_Line_Field(field) &&
2316 (Maybe_Done || Growable(field)))
2318 if (!Maybe_Done && !Field_Grown(field,1))
2319 result = E_SYSTEM_ERROR;
2331 /*---------------------------------------------------------------------------
2332 | Facility : libnform
2333 | Function : static int FE_Delete_Character(FORM * form)
2335 | Description : Delete character at the cursor position
2337 | Return Values : E_OK - success
2338 +--------------------------------------------------------------------------*/
2339 static int FE_Delete_Character(FORM * form)
2345 /*---------------------------------------------------------------------------
2346 | Facility : libnform
2347 | Function : static int FE_Delete_Previous(FORM * form)
2349 | Description : Delete character before cursor. Again this is a rather
2350 | difficult piece compared to others due to the overloading
2351 | semantics of backspace.
2352 | N.B.: The case of overloaded BS on first field position
2353 | is already handled in the generic routine.
2355 | Return Values : E_OK - success
2356 | E_REQUEST_DENIED - Character can't be deleted
2357 +--------------------------------------------------------------------------*/
2358 static int FE_Delete_Previous(FORM * form)
2360 FIELD *field = form->current;
2362 if (First_Position_In_Current_Field(form))
2363 return E_REQUEST_DENIED;
2365 if ( (--(form->curcol))<0 )
2367 char *this_line, *prev_line, *prev_end, *this_end;
2370 if (form->status & _OVLMODE)
2371 return E_REQUEST_DENIED;
2373 prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
2374 this_line = Address_Of_Row_In_Buffer(field,(form->currow));
2375 Synchronize_Buffer(form);
2376 prev_end = After_End_Of_Data(prev_line,field->dcols);
2377 this_end = After_End_Of_Data(this_line,field->dcols);
2378 if ((int)(this_end-this_line) >
2379 (field->cols-(int)(prev_end-prev_line)))
2380 return E_REQUEST_DENIED;
2382 Adjust_Cursor_Position(form,prev_end);
2383 wmove(form->w,form->currow,form->curcol);
2384 waddnstr(form->w,this_line,(int)(this_end-this_line));
2388 wmove(form->w,form->currow,form->curcol);
2394 /*---------------------------------------------------------------------------
2395 | Facility : libnform
2396 | Function : static int FE_Delete_Line(FORM * form)
2398 | Description : Delete line at cursor position.
2400 | Return Values : E_OK - success
2401 +--------------------------------------------------------------------------*/
2402 static int FE_Delete_Line(FORM * form)
2409 /*---------------------------------------------------------------------------
2410 | Facility : libnform
2411 | Function : static int FE_Delete_Word(FORM * form)
2413 | Description : Delete word at cursor position
2415 | Return Values : E_OK - success
2416 | E_REQUEST_DENIED - failure
2417 +--------------------------------------------------------------------------*/
2418 static int FE_Delete_Word(FORM * form)
2420 FIELD *field = form->current;
2421 char *bp = Address_Of_Current_Row_In_Buffer(form);
2422 char *ep = bp + field->dcols;
2423 char *cp = bp + form->curcol;
2426 Synchronize_Buffer(form);
2428 return E_REQUEST_DENIED; /* not in word */
2430 /* move cursor to begin of word and erase to end of screen-line */
2431 Adjust_Cursor_Position(form,
2432 After_Last_Whitespace_Character(bp,form->curcol));
2433 wmove(form->w,form->currow,form->curcol);
2436 /* skip over word in buffer */
2437 s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
2438 /* to begin of next word */
2439 s = Get_Start_Of_Data(s,(int)(ep - s));
2440 if ( (s!=cp) && !is_blank(*s))
2442 /* copy remaining line to window */
2443 waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
2448 /*---------------------------------------------------------------------------
2449 | Facility : libnform
2450 | Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2452 | Description : Clear to end of current line.
2454 | Return Values : E_OK - success
2455 +--------------------------------------------------------------------------*/
2456 static int FE_Clear_To_End_Of_Line(FORM * form)
2462 /*---------------------------------------------------------------------------
2463 | Facility : libnform
2464 | Function : static int FE_Clear_To_End_Of_Form(FORM * form)
2466 | Description : Clear to end of form.
2468 | Return Values : E_OK - success
2469 +--------------------------------------------------------------------------*/
2470 static int FE_Clear_To_End_Of_Form(FORM * form)
2476 /*---------------------------------------------------------------------------
2477 | Facility : libnform
2478 | Function : static int FE_Clear_Field(FORM * form)
2480 | Description : Clear entire field.
2482 | Return Values : E_OK - success
2483 +--------------------------------------------------------------------------*/
2484 static int FE_Clear_Field(FORM * form)
2486 form->currow = form->curcol = 0;
2490 /*----------------------------------------------------------------------------
2491 END of Field Editing routines
2492 --------------------------------------------------------------------------*/
2494 /*----------------------------------------------------------------------------
2496 --------------------------------------------------------------------------*/
2498 /*---------------------------------------------------------------------------
2499 | Facility : libnform
2500 | Function : static int EM_Overlay_Mode(FORM * form)
2502 | Description : Switch to overlay mode.
2504 | Return Values : E_OK - success
2505 +--------------------------------------------------------------------------*/
2506 static int EM_Overlay_Mode(FORM * form)
2508 form->status |= _OVLMODE;
2512 /*---------------------------------------------------------------------------
2513 | Facility : libnform
2514 | Function : static int EM_Insert_Mode(FORM * form)
2516 | Description : Switch to insert mode
2518 | Return Values : E_OK - success
2519 +--------------------------------------------------------------------------*/
2520 static int EM_Insert_Mode(FORM * form)
2522 form->status &= ~_OVLMODE;
2526 /*----------------------------------------------------------------------------
2527 END of Edit Mode routines
2528 --------------------------------------------------------------------------*/
2530 /*----------------------------------------------------------------------------
2531 Helper routines for Choice Requests
2532 --------------------------------------------------------------------------*/
2534 /*---------------------------------------------------------------------------
2535 | Facility : libnform
2536 | Function : static bool Next_Choice(
2539 | TypeArgument *argp)
2541 | Description : Get the next field choice. For linked types this is
2544 | Return Values : TRUE - next choice successfully retrieved
2545 | FALSE - couldn't retrieve next choice
2546 +--------------------------------------------------------------------------*/
2547 static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
2549 if (!typ || !(typ->status & _HAS_CHOICE))
2552 if (typ->status & _LINKED_TYPE)
2556 Next_Choice(typ->left ,field,argp->left) ||
2557 Next_Choice(typ->right,field,argp->right) );
2562 return typ->next(field,(void *)argp);
2566 /*---------------------------------------------------------------------------
2567 | Facility : libnform
2568 | Function : static bool Previous_Choice(
2571 | TypeArgument *argp)
2573 | Description : Get the previous field choice. For linked types this
2574 | is done recursively.
2576 | Return Values : TRUE - previous choice successfully retrieved
2577 | FALSE - couldn't retrieve previous choice
2578 +--------------------------------------------------------------------------*/
2579 static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2581 if (!typ || !(typ->status & _HAS_CHOICE))
2584 if (typ->status & _LINKED_TYPE)
2588 Previous_Choice(typ->left ,field,argp->left) ||
2589 Previous_Choice(typ->right,field,argp->right));
2594 return typ->prev(field,(void *)argp);
2597 /*----------------------------------------------------------------------------
2598 End of Helper routines for Choice Requests
2599 --------------------------------------------------------------------------*/
2601 /*----------------------------------------------------------------------------
2602 Routines for Choice Requests
2603 --------------------------------------------------------------------------*/
2605 /*---------------------------------------------------------------------------
2606 | Facility : libnform
2607 | Function : static int CR_Next_Choice(FORM * form)
2609 | Description : Get the next field choice.
2611 | Return Values : E_OK - success
2612 | E_REQUEST_DENIED - next choice couldn't be retrieved
2613 +--------------------------------------------------------------------------*/
2614 static int CR_Next_Choice(FORM * form)
2616 FIELD *field = form->current;
2617 Synchronize_Buffer(form);
2618 return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2619 E_OK : E_REQUEST_DENIED);
2622 /*---------------------------------------------------------------------------
2623 | Facility : libnform
2624 | Function : static int CR_Previous_Choice(FORM * form)
2626 | Description : Get the previous field choice.
2628 | Return Values : E_OK - success
2629 | E_REQUEST_DENIED - prev. choice couldn't be retrieved
2630 +--------------------------------------------------------------------------*/
2631 static int CR_Previous_Choice(FORM * form)
2633 FIELD *field = form->current;
2634 Synchronize_Buffer(form);
2635 return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2636 E_OK : E_REQUEST_DENIED);
2638 /*----------------------------------------------------------------------------
2639 End of Routines for Choice Requests
2640 --------------------------------------------------------------------------*/
2642 /*----------------------------------------------------------------------------
2643 Helper routines for Field Validations.
2644 --------------------------------------------------------------------------*/
2646 /*---------------------------------------------------------------------------
2647 | Facility : libnform
2648 | Function : static bool Check_Field(
2651 | TypeArgument * argp)
2653 | Description : Check the field according to its fieldtype and its
2654 | actual arguments. For linked fieldtypes this is done
2657 | Return Values : TRUE - field is valid
2658 | FALSE - field is invalid.
2659 +--------------------------------------------------------------------------*/
2660 static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2664 if (field->opts & O_NULLOK)
2666 char *bp = field->buf;
2668 while(is_blank(*bp))
2674 if (typ->status & _LINKED_TYPE)
2678 Check_Field(typ->left ,field,argp->left ) ||
2679 Check_Field(typ->right,field,argp->right) );
2684 return typ->fcheck(field,(void *)argp);
2690 /*---------------------------------------------------------------------------
2691 | Facility : libnform
2692 | Function : bool _nc_Internal_Validation(FORM * form )
2694 | Description : Validate the current field of the form.
2696 | Return Values : TRUE - field is valid
2697 | FALSE - field is invalid
2698 +--------------------------------------------------------------------------*/
2699 NCURSES_EXPORT(bool)
2700 _nc_Internal_Validation (FORM *form)
2704 field = form->current;
2706 Synchronize_Buffer(form);
2707 if ((form->status & _FCHECK_REQUIRED) ||
2708 (!(field->opts & O_PASSOK)))
2710 if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
2712 form->status &= ~_FCHECK_REQUIRED;
2713 field->status |= _CHANGED;
2714 Synchronize_Linked_Fields(field);
2718 /*----------------------------------------------------------------------------
2719 End of Helper routines for Field Validations.
2720 --------------------------------------------------------------------------*/
2722 /*----------------------------------------------------------------------------
2723 Routines for Field Validation.
2724 --------------------------------------------------------------------------*/
2726 /*---------------------------------------------------------------------------
2727 | Facility : libnform
2728 | Function : static int FV_Validation(FORM * form)
2730 | Description : Validate the current field of the form.
2732 | Return Values : E_OK - field valid
2733 | E_INVALID_FIELD - field not valid
2734 +--------------------------------------------------------------------------*/
2735 static int FV_Validation(FORM * form)
2737 if (_nc_Internal_Validation(form))
2740 return E_INVALID_FIELD;
2742 /*----------------------------------------------------------------------------
2743 End of routines for Field Validation.
2744 --------------------------------------------------------------------------*/
2746 /*----------------------------------------------------------------------------
2747 Helper routines for Inter-Field Navigation
2748 --------------------------------------------------------------------------*/
2750 /*---------------------------------------------------------------------------
2751 | Facility : libnform
2752 | Function : static FIELD *Next_Field_On_Page(FIELD * field)
2754 | Description : Get the next field after the given field on the current
2755 | page. The order of fields is the one defined by the
2756 | fields array. Only visible and active fields are
2759 | Return Values : Pointer to the next field.
2760 +--------------------------------------------------------------------------*/
2761 INLINE static FIELD *Next_Field_On_Page(FIELD * field)
2763 FORM *form = field->form;
2764 FIELD **field_on_page = &form->field[field->index];
2765 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2766 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2771 (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
2772 if (Field_Is_Selectable(*field_on_page))
2774 } while(field!=(*field_on_page));
2775 return(*field_on_page);
2778 /*---------------------------------------------------------------------------
2779 | Facility : libnform
2780 | Function : FIELD* _nc_First_Active_Field(FORM * form)
2782 | Description : Get the first active field on the current page,
2783 | if there are such. If there are none, get the first
2784 | visible field on the page. If there are also none,
2785 | we return the first field on page and hope the best.
2787 | Return Values : Pointer to calculated field.
2788 +--------------------------------------------------------------------------*/
2789 NCURSES_EXPORT(FIELD*)
2790 _nc_First_Active_Field (FORM * form)
2792 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2793 FIELD *proposed = Next_Field_On_Page(*last_on_page);
2795 if (proposed == *last_on_page)
2796 { /* there might be the special situation, where there is no
2797 active and visible field on the current page. We then select
2798 the first visible field on this readonly page
2800 if (Field_Is_Not_Selectable(proposed))
2802 FIELD **field = &form->field[proposed->index];
2803 FIELD **first = &form->field[form->page[form->curpage].pmin];
2807 field = (field==last_on_page) ? first : field + 1;
2808 if (((*field)->opts & O_VISIBLE))
2810 } while(proposed!=(*field));
2814 if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
2815 { /* This means, there is also no visible field on the page.
2816 So we propose the first one and hope the very best...
2817 Some very clever user has designed a readonly and invisible
2827 /*---------------------------------------------------------------------------
2828 | Facility : libnform
2829 | Function : static FIELD *Previous_Field_On_Page(FIELD * field)
2831 | Description : Get the previous field before the given field on the
2832 | current page. The order of fields is the one defined by
2833 | the fields array. Only visible and active fields are
2836 | Return Values : Pointer to the previous field.
2837 +--------------------------------------------------------------------------*/
2838 INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
2840 FORM *form = field->form;
2841 FIELD **field_on_page = &form->field[field->index];
2842 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2843 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2848 (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
2849 if (Field_Is_Selectable(*field_on_page))
2851 } while(field!=(*field_on_page));
2853 return (*field_on_page);
2856 /*---------------------------------------------------------------------------
2857 | Facility : libnform
2858 | Function : static FIELD *Sorted_Next_Field(FIELD * field)
2860 | Description : Get the next field after the given field on the current
2861 | page. The order of fields is the one defined by the
2862 | (row,column) geometry, rows are major.
2864 | Return Values : Pointer to the next field.
2865 +--------------------------------------------------------------------------*/
2866 INLINE static FIELD *Sorted_Next_Field(FIELD * field)
2868 FIELD *field_on_page = field;
2872 field_on_page = field_on_page->snext;
2873 if (Field_Is_Selectable(field_on_page))
2875 } while(field_on_page!=field);
2877 return (field_on_page);
2880 /*---------------------------------------------------------------------------
2881 | Facility : libnform
2882 | Function : static FIELD *Sorted_Previous_Field(FIELD * field)
2884 | Description : Get the previous field before the given field on the
2885 | current page. The order of fields is the one defined
2886 | by the (row,column) geometry, rows are major.
2888 | Return Values : Pointer to the previous field.
2889 +--------------------------------------------------------------------------*/
2890 INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
2892 FIELD *field_on_page = field;
2896 field_on_page = field_on_page->sprev;
2897 if (Field_Is_Selectable(field_on_page))
2899 } while(field_on_page!=field);
2901 return (field_on_page);
2904 /*---------------------------------------------------------------------------
2905 | Facility : libnform
2906 | Function : static FIELD *Left_Neighbour_Field(FIELD * field)
2908 | Description : Get the left neighbour of the field on the same line
2909 | and the same page. Cycles through the line.
2911 | Return Values : Pointer to left neighbour field.
2912 +--------------------------------------------------------------------------*/
2913 INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
2915 FIELD *field_on_page = field;
2917 /* For a field that has really a left neighbour, the while clause
2918 immediately fails and the loop is left, positioned at the right
2919 neighbour. Otherwise we cycle backwards through the sorted fieldlist
2920 until we enter the same line (from the right end).
2924 field_on_page = Sorted_Previous_Field(field_on_page);
2925 } while(field_on_page->frow != field->frow);
2927 return (field_on_page);
2930 /*---------------------------------------------------------------------------
2931 | Facility : libnform
2932 | Function : static FIELD *Right_Neighbour_Field(FIELD * field)
2934 | Description : Get the right neighbour of the field on the same line
2935 | and the same page.
2937 | Return Values : Pointer to right neighbour field.
2938 +--------------------------------------------------------------------------*/
2939 INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
2941 FIELD *field_on_page = field;
2943 /* See the comments on Left_Neighbour_Field to understand how it works */
2946 field_on_page = Sorted_Next_Field(field_on_page);
2947 } while(field_on_page->frow != field->frow);
2949 return (field_on_page);
2952 /*---------------------------------------------------------------------------
2953 | Facility : libnform
2954 | Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
2956 | Description : Because of the row-major nature of sorting the fields,
2957 | its more difficult to define whats the upper neighbour
2958 | field really means. We define that it must be on a
2959 | 'previous' line (cyclic order!) and is the rightmost
2960 | field laying on the left side of the given field. If
2961 | this set is empty, we take the first field on the line.
2963 | Return Values : Pointer to the upper neighbour field.
2964 +--------------------------------------------------------------------------*/
2965 static FIELD *Upper_Neighbour_Field(FIELD * field)
2967 FIELD *field_on_page = field;
2968 int frow = field->frow;
2969 int fcol = field->fcol;
2971 /* Walk back to the 'previous' line. The second term in the while clause
2972 just guarantees that we stop if we cycled through the line because
2973 there might be no 'previous' line if the page has just one line.
2977 field_on_page = Sorted_Previous_Field(field_on_page);
2978 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
2980 if (field_on_page->frow!=frow)
2981 { /* We really found a 'previous' line. We are positioned at the
2982 rightmost field on this line */
2983 frow = field_on_page->frow;
2985 /* We walk to the left as long as we are really right of the
2987 while(field_on_page->frow==frow && field_on_page->fcol>fcol)
2988 field_on_page = Sorted_Previous_Field(field_on_page);
2990 /* If we wrapped, just go to the right which is the first field on
2992 if (field_on_page->frow!=frow)
2993 field_on_page = Sorted_Next_Field(field_on_page);
2996 return (field_on_page);
2999 /*---------------------------------------------------------------------------
3000 | Facility : libnform
3001 | Function : static FIELD *Down_Neighbour_Field(FIELD * field)
3003 | Description : Because of the row-major nature of sorting the fields,
3004 | its more difficult to define whats the down neighbour
3005 | field really means. We define that it must be on a
3006 | 'next' line (cyclic order!) and is the leftmost
3007 | field laying on the right side of the given field. If
3008 | this set is empty, we take the last field on the line.
3010 | Return Values : Pointer to the upper neighbour field.
3011 +--------------------------------------------------------------------------*/
3012 static FIELD *Down_Neighbour_Field(FIELD * field)
3014 FIELD *field_on_page = field;
3015 int frow = field->frow;
3016 int fcol = field->fcol;
3018 /* Walk forward to the 'next' line. The second term in the while clause
3019 just guarantees that we stop if we cycled through the line because
3020 there might be no 'next' line if the page has just one line.
3024 field_on_page = Sorted_Next_Field(field_on_page);
3025 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3027 if (field_on_page->frow!=frow)
3028 { /* We really found a 'next' line. We are positioned at the rightmost
3029 field on this line */
3030 frow = field_on_page->frow;
3032 /* We walk to the right as long as we are really left of the
3034 while(field_on_page->frow==frow && field_on_page->fcol<fcol)
3035 field_on_page = Sorted_Next_Field(field_on_page);
3037 /* If we wrapped, just go to the left which is the last field on
3039 if (field_on_page->frow!=frow)
3040 field_on_page = Sorted_Previous_Field(field_on_page);
3043 return(field_on_page);
3046 /*----------------------------------------------------------------------------
3047 Inter-Field Navigation routines
3048 --------------------------------------------------------------------------*/
3050 /*---------------------------------------------------------------------------
3051 | Facility : libnform
3052 | Function : static int Inter_Field_Navigation(
3053 | int (* const fct) (FORM *),
3056 | Description : Generic behaviour for changing the current field, the
3057 | field is left and a new field is entered. So the field
3058 | must be validated and the field init/term hooks must
3061 | Return Values : E_OK - success
3062 | E_INVALID_FIELD - field is invalid
3063 | some other - error from subordinate call
3064 +--------------------------------------------------------------------------*/
3065 static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
3069 if (!_nc_Internal_Validation(form))
3070 res = E_INVALID_FIELD;
3073 Call_Hook(form,fieldterm);
3075 Call_Hook(form,fieldinit);
3080 /*---------------------------------------------------------------------------
3081 | Facility : libnform
3082 | Function : static int FN_Next_Field(FORM * form)
3084 | Description : Move to the next field on the current page of the form
3086 | Return Values : E_OK - success
3087 | != E_OK - error from subordinate call
3088 +--------------------------------------------------------------------------*/
3089 static int FN_Next_Field(FORM * form)
3091 return _nc_Set_Current_Field(form,
3092 Next_Field_On_Page(form->current));
3095 /*---------------------------------------------------------------------------
3096 | Facility : libnform
3097 | Function : static int FN_Previous_Field(FORM * form)
3099 | Description : Move to the previous field on the current page of the
3102 | Return Values : E_OK - success
3103 | != E_OK - error from subordinate call
3104 +--------------------------------------------------------------------------*/
3105 static int FN_Previous_Field(FORM * form)
3107 return _nc_Set_Current_Field(form,
3108 Previous_Field_On_Page(form->current));
3111 /*---------------------------------------------------------------------------
3112 | Facility : libnform
3113 | Function : static int FN_First_Field(FORM * form)
3115 | Description : Move to the first field on the current page of the form
3117 | Return Values : E_OK - success
3118 | != E_OK - error from subordinate call
3119 +--------------------------------------------------------------------------*/
3120 static int FN_First_Field(FORM * form)
3122 return _nc_Set_Current_Field(form,
3123 Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
3126 /*---------------------------------------------------------------------------
3127 | Facility : libnform
3128 | Function : static int FN_Last_Field(FORM * form)
3130 | Description : Move to the last field on the current page of the form
3132 | Return Values : E_OK - success
3133 | != E_OK - error from subordinate call
3134 +--------------------------------------------------------------------------*/
3135 static int FN_Last_Field(FORM * form)
3138 _nc_Set_Current_Field(form,
3139 Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
3142 /*---------------------------------------------------------------------------
3143 | Facility : libnform
3144 | Function : static int FN_Sorted_Next_Field(FORM * form)
3146 | Description : Move to the sorted next field on the current page
3149 | Return Values : E_OK - success
3150 | != E_OK - error from subordinate call
3151 +--------------------------------------------------------------------------*/
3152 static int FN_Sorted_Next_Field(FORM * form)
3154 return _nc_Set_Current_Field(form,
3155 Sorted_Next_Field(form->current));
3158 /*---------------------------------------------------------------------------
3159 | Facility : libnform
3160 | Function : static int FN_Sorted_Previous_Field(FORM * form)
3162 | Description : Move to the sorted previous field on the current page
3165 | Return Values : E_OK - success
3166 | != E_OK - error from subordinate call
3167 +--------------------------------------------------------------------------*/
3168 static int FN_Sorted_Previous_Field(FORM * form)
3170 return _nc_Set_Current_Field(form,
3171 Sorted_Previous_Field(form->current));
3174 /*---------------------------------------------------------------------------
3175 | Facility : libnform
3176 | Function : static int FN_Sorted_First_Field(FORM * form)
3178 | Description : Move to the sorted first field on the current page
3181 | Return Values : E_OK - success
3182 | != E_OK - error from subordinate call
3183 +--------------------------------------------------------------------------*/
3184 static int FN_Sorted_First_Field(FORM * form)
3186 return _nc_Set_Current_Field(form,
3187 Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
3190 /*---------------------------------------------------------------------------
3191 | Facility : libnform
3192 | Function : static int FN_Sorted_Last_Field(FORM * form)
3194 | Description : Move to the sorted last field on the current page
3197 | Return Values : E_OK - success
3198 | != E_OK - error from subordinate call
3199 +--------------------------------------------------------------------------*/
3200 static int FN_Sorted_Last_Field(FORM * form)
3202 return _nc_Set_Current_Field(form,
3203 Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
3206 /*---------------------------------------------------------------------------
3207 | Facility : libnform
3208 | Function : static int FN_Left_Field(FORM * form)
3210 | Description : Get the field on the left of the current field on the
3211 | same line and the same page. Cycles through the line.
3213 | Return Values : E_OK - success
3214 | != E_OK - error from subordinate call
3215 +--------------------------------------------------------------------------*/
3216 static int FN_Left_Field(FORM * form)
3218 return _nc_Set_Current_Field(form,
3219 Left_Neighbour_Field(form->current));
3222 /*---------------------------------------------------------------------------
3223 | Facility : libnform
3224 | Function : static int FN_Right_Field(FORM * form)
3226 | Description : Get the field on the right of the current field on the
3227 | same line and the same page. Cycles through the line.
3229 | Return Values : E_OK - success
3230 | != E_OK - error from subordinate call
3231 +--------------------------------------------------------------------------*/
3232 static int FN_Right_Field(FORM * form)
3234 return _nc_Set_Current_Field(form,
3235 Right_Neighbour_Field(form->current));
3238 /*---------------------------------------------------------------------------
3239 | Facility : libnform
3240 | Function : static int FN_Up_Field(FORM * form)
3242 | Description : Get the upper neighbour of the current field. This
3243 | cycles through the page. See the comments of the
3244 | Upper_Neighbour_Field function to understand how
3245 | 'upper' is defined.
3247 | Return Values : E_OK - success
3248 | != E_OK - error from subordinate call
3249 +--------------------------------------------------------------------------*/
3250 static int FN_Up_Field(FORM * form)
3252 return _nc_Set_Current_Field(form,
3253 Upper_Neighbour_Field(form->current));
3256 /*---------------------------------------------------------------------------
3257 | Facility : libnform
3258 | Function : static int FN_Down_Field(FORM * form)
3260 | Description : Get the down neighbour of the current field. This
3261 | cycles through the page. See the comments of the
3262 | Down_Neighbour_Field function to understand how
3263 | 'down' is defined.
3265 | Return Values : E_OK - success
3266 | != E_OK - error from subordinate call
3267 +--------------------------------------------------------------------------*/
3268 static int FN_Down_Field(FORM * form)
3270 return _nc_Set_Current_Field(form,
3271 Down_Neighbour_Field(form->current));
3273 /*----------------------------------------------------------------------------
3274 END of Field Navigation routines
3275 --------------------------------------------------------------------------*/
3277 /*----------------------------------------------------------------------------
3278 Helper routines for Page Navigation
3279 --------------------------------------------------------------------------*/
3281 /*---------------------------------------------------------------------------
3282 | Facility : libnform
3283 | Function : int _nc_Set_Form_Page(FORM * form,
3287 | Description : Make the given page nr. the current page and make
3288 | the given field the current field on the page. If
3289 | for the field NULL is given, make the first field on
3290 | the page the current field. The routine acts only
3291 | if the requested page is not the current page.
3293 | Return Values : E_OK - success
3294 | != E_OK - error from subordinate call
3295 +--------------------------------------------------------------------------*/
3298 (FORM * form, int page, FIELD * field)
3302 if ((form->curpage!=page))
3304 FIELD *last_field, *field_on_page;
3306 werase(Get_Form_Window(form));
3307 form->curpage = page;
3308 last_field = field_on_page = form->field[form->page[page].smin];
3311 if (field_on_page->opts & O_VISIBLE)
3312 if ((res=Display_Field(field_on_page))!=E_OK)
3314 field_on_page = field_on_page->snext;
3315 } while(field_on_page != last_field);
3318 res = _nc_Set_Current_Field(form,field);
3320 /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
3321 because this is already executed in a page navigation
3322 context that contains field navigation
3324 res = FN_First_Field(form);
3329 /*---------------------------------------------------------------------------
3330 | Facility : libnform
3331 | Function : static int Next_Page_Number(const FORM * form)
3333 | Description : Calculate the page number following the current page
3334 | number. This cycles if the highest page number is
3337 | Return Values : The next page number
3338 +--------------------------------------------------------------------------*/
3339 INLINE static int Next_Page_Number(const FORM * form)
3341 return (form->curpage + 1) % form->maxpage;
3344 /*---------------------------------------------------------------------------
3345 | Facility : libnform
3346 | Function : static int Previous_Page_Number(const FORM * form)
3348 | Description : Calculate the page number before the current page
3349 | number. This cycles if the first page number is
3352 | Return Values : The previous page number
3353 +--------------------------------------------------------------------------*/
3354 INLINE static int Previous_Page_Number(const FORM * form)
3356 return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
3359 /*----------------------------------------------------------------------------
3360 Page Navigation routines
3361 --------------------------------------------------------------------------*/
3363 /*---------------------------------------------------------------------------
3364 | Facility : libnform
3365 | Function : static int Page_Navigation(
3366 | int (* const fct) (FORM *),
3369 | Description : Generic behaviour for changing a page. This means
3370 | that the field is left and a new field is entered.
3371 | So the field must be validated and the field init/term
3372 | hooks must be called. Because also the page is changed,
3373 | the forms init/term hooks must be called also.
3375 | Return Values : E_OK - success
3376 | E_INVALID_FIELD - field is invalid
3377 | some other - error from subordinate call
3378 +--------------------------------------------------------------------------*/
3379 static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
3383 if (!_nc_Internal_Validation(form))
3384 res = E_INVALID_FIELD;
3387 Call_Hook(form,fieldterm);
3388 Call_Hook(form,formterm);
3390 Call_Hook(form,forminit);
3391 Call_Hook(form,fieldinit);
3396 /*---------------------------------------------------------------------------
3397 | Facility : libnform
3398 | Function : static int PN_Next_Page(FORM * form)
3400 | Description : Move to the next page of the form
3402 | Return Values : E_OK - success
3403 | != E_OK - error from subordinate call
3404 +--------------------------------------------------------------------------*/
3405 static int PN_Next_Page(FORM * form)
3407 return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
3410 /*---------------------------------------------------------------------------
3411 | Facility : libnform
3412 | Function : static int PN_Previous_Page(FORM * form)
3414 | Description : Move to the previous page of the form
3416 | Return Values : E_OK - success
3417 | != E_OK - error from subordinate call
3418 +--------------------------------------------------------------------------*/
3419 static int PN_Previous_Page(FORM * form)
3421 return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
3424 /*---------------------------------------------------------------------------
3425 | Facility : libnform
3426 | Function : static int PN_First_Page(FORM * form)
3428 | Description : Move to the first page of the form
3430 | Return Values : E_OK - success
3431 | != E_OK - error from subordinate call
3432 +--------------------------------------------------------------------------*/
3433 static int PN_First_Page(FORM * form)
3435 return _nc_Set_Form_Page(form,0,(FIELD *)0);
3438 /*---------------------------------------------------------------------------
3439 | Facility : libnform
3440 | Function : static int PN_Last_Page(FORM * form)
3442 | Description : Move to the last page of the form
3444 | Return Values : E_OK - success
3445 | != E_OK - error from subordinate call
3446 +--------------------------------------------------------------------------*/
3447 static int PN_Last_Page(FORM * form)
3449 return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
3451 /*----------------------------------------------------------------------------
3452 END of Field Navigation routines
3453 --------------------------------------------------------------------------*/
3455 /*----------------------------------------------------------------------------
3456 Helper routines for the core form driver.
3457 --------------------------------------------------------------------------*/
3459 /*---------------------------------------------------------------------------
3460 | Facility : libnform
3461 | Function : static int Data_Entry(FORM * form,int c)
3463 | Description : Enter character c into at the current position of the
3464 | current field of the form.
3466 | Return Values : E_OK -
3467 | E_REQUEST_DENIED -
3469 +--------------------------------------------------------------------------*/
3470 static int Data_Entry(FORM * form, int c)
3472 FIELD *field = form->current;
3473 int result = E_REQUEST_DENIED;
3475 if ( (field->opts & O_EDIT)
3476 #if FIX_FORM_INACTIVE_BUG
3477 && (field->opts & O_ACTIVE)
3481 if ( (field->opts & O_BLANK) &&
3482 First_Position_In_Current_Field(form) &&
3483 !(form->status & _FCHECK_REQUIRED) &&
3484 !(form->status & _WINDOW_MODIFIED) )
3487 if (form->status & _OVLMODE)
3489 waddch(form->w,(chtype)c);
3491 else /* no _OVLMODE */
3493 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
3495 if (!(There_Is_Room ||
3496 ((Single_Line_Field(field) && Growable(field)))))
3497 return E_REQUEST_DENIED;
3499 if (!There_Is_Room && !Field_Grown(field,1))
3500 return E_SYSTEM_ERROR;
3502 winsch(form->w,(chtype)c);
3505 if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
3507 bool End_Of_Field= (((field->drows-1)==form->currow) &&
3508 ((field->dcols-1)==form->curcol));
3509 form->status |= _WINDOW_MODIFIED;
3510 if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3511 result = Inter_Field_Navigation(FN_Next_Field,form);
3514 if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
3515 result = E_SYSTEM_ERROR;
3518 IFN_Next_Character(form);
3527 /* Structure to describe the binding of a request code to a function.
3528 The member keycode codes the request value as well as the generic
3529 routine to use for the request. The code for the generic routine
3530 is coded in the upper 16 Bits while the request code is coded in
3533 In terms of C++ you might think of a request as a class with a
3534 virtual method "perform". The different types of request are
3535 derived from this base class and overload (or not) the base class
3536 implementation of perform.
3539 int keycode; /* must be at least 32 bit: hi:mode, lo: key */
3540 int (*cmd)(FORM *); /* low level driver routine for this key */
3543 /* You may see this is the class-id of the request type class */
3544 #define ID_PN (0x00000000) /* Page navigation */
3545 #define ID_FN (0x00010000) /* Inter-Field navigation */
3546 #define ID_IFN (0x00020000) /* Intra-Field navigation */
3547 #define ID_VSC (0x00030000) /* Vertical Scrolling */
3548 #define ID_HSC (0x00040000) /* Horizontal Scrolling */
3549 #define ID_FE (0x00050000) /* Field Editing */
3550 #define ID_EM (0x00060000) /* Edit Mode */
3551 #define ID_FV (0x00070000) /* Field Validation */
3552 #define ID_CH (0x00080000) /* Choice */
3553 #define ID_Mask (0xffff0000)
3554 #define Key_Mask (0x0000ffff)
3555 #define ID_Shft (16)
3557 /* This array holds all the Binding Infos */
3558 static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
3560 { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
3561 { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
3562 { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
3563 { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
3565 { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
3566 { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
3567 { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
3568 { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
3569 { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
3570 { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
3571 { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
3572 { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
3573 { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
3574 { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
3575 { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
3576 { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
3578 { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
3579 { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
3580 { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
3581 { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
3582 { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
3583 { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
3584 { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
3585 { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
3586 { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
3587 { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
3588 { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
3589 { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
3590 { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
3591 { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
3593 { REQ_NEW_LINE |ID_FE ,FE_New_Line},
3594 { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
3595 { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
3596 { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
3597 { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
3598 { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
3599 { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
3600 { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
3601 { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
3602 { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
3604 { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
3605 { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
3607 { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
3608 { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
3609 { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
3610 { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
3611 { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
3612 { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
3614 { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
3615 { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
3616 { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
3617 { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
3618 { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
3619 { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
3621 { REQ_VALIDATION |ID_FV ,FV_Validation},
3623 { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
3624 { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
3627 /*---------------------------------------------------------------------------
3628 | Facility : libnform
3629 | Function : int form_driver(FORM * form,int c)
3631 | Description : This is the workhorse of the forms system. It checks
3632 | to determine whether the character c is a request or
3633 | data. If it is a request, the form driver executes
3634 | the request and returns the result. If it is data
3635 | (printable character), it enters the data into the
3636 | current position in the current field. If it is not
3637 | recognized, the form driver assumes it is an application
3638 | defined command and returns E_UNKNOWN_COMMAND.
3639 | Application defined command should be defined relative
3640 | to MAX_FORM_COMMAND, the maximum value of a request.
3642 | Return Values : E_OK - success
3643 | E_SYSTEM_ERROR - system error
3644 | E_BAD_ARGUMENT - an argument is incorrect
3645 | E_NOT_POSTED - form is not posted
3646 | E_INVALID_FIELD - field contents are invalid
3647 | E_BAD_STATE - called from inside a hook routine
3648 | E_REQUEST_DENIED - request failed
3649 | E_UNKNOWN_COMMAND - command not known
3650 +--------------------------------------------------------------------------*/
3652 form_driver (FORM * form, int c)
3654 const Binding_Info* BI = (Binding_Info *)0;
3655 int res = E_UNKNOWN_COMMAND;
3658 RETURN(E_BAD_ARGUMENT);
3661 RETURN(E_NOT_CONNECTED);
3665 if (c==FIRST_ACTIVE_MAGIC)
3667 form->current = _nc_First_Active_Field(form);
3671 assert(form->current &&
3672 form->current->buf &&
3673 (form->current->form == form)
3676 if ( form->status & _IN_DRIVER )
3677 RETURN(E_BAD_STATE);
3679 if ( !( form->status & _POSTED ) )
3680 RETURN(E_NOT_POSTED);
3682 if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
3683 ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
3684 BI = &(bindings[c-MIN_FORM_COMMAND]);
3688 typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
3689 static const Generic_Method Generic_Methods[] =
3691 Page_Navigation, /* overloaded to call field&form hooks */
3692 Inter_Field_Navigation, /* overloaded to call field hooks */
3693 NULL, /* Intra-Field is generic */
3694 Vertical_Scrolling, /* Overloaded to check multi-line */
3695 Horizontal_Scrolling, /* Overloaded to check single-line */
3696 Field_Editing, /* Overloaded to mark modification */
3697 NULL, /* Edit Mode is generic */
3698 NULL, /* Field Validation is generic */
3699 NULL /* Choice Request is generic */
3701 size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
3702 size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
3704 if ( (method >= nMethods) || !(BI->cmd) )
3705 res = E_SYSTEM_ERROR;
3708 Generic_Method fct = Generic_Methods[method];
3710 res = fct(BI->cmd,form);
3712 res = (BI->cmd)(form);
3717 if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
3718 isprint((unsigned char)c) &&
3719 Check_Char(form->current->type,c,
3720 (TypeArgument *)(form->current->arg)))
3721 res = Data_Entry(form,c);
3723 _nc_Refresh_Current_Field(form);
3727 /*----------------------------------------------------------------------------
3728 Field-Buffer manipulation routines.
3729 The effects of setting a buffer is tightly coupled to the core of the form
3730 driver logic. This is especially true in the case of growable fields.
3731 So I don't separate this into an own module.
3732 --------------------------------------------------------------------------*/
3734 /*---------------------------------------------------------------------------
3735 | Facility : libnform
3736 | Function : int set_field_buffer(FIELD *field,
3737 | int buffer, char *value)
3739 | Description : Set the given buffer of the field to the given value.
3740 | Buffer 0 stores the displayed content of the field.
3741 | For dynamic fields this may grow the fieldbuffers if
3742 | the length of the value exceeds the current buffer
3743 | length. For buffer 0 only printable values are allowed.
3744 | For static fields, the value needs not to be zero ter-
3745 | minated. It is copied up to the length of the buffer.
3747 | Return Values : E_OK - success
3748 | E_BAD_ARGUMENT - invalid argument
3749 | E_SYSTEM_ERROR - system error
3750 +--------------------------------------------------------------------------*/
3753 (FIELD * field, int buffer, const char * value)
3759 if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
3760 RETURN(E_BAD_ARGUMENT);
3762 len = Buffer_Length(field);
3769 for(v=value; *v && (i<len); v++,i++)
3771 if (!isprint((unsigned char)*v))
3772 RETURN(E_BAD_ARGUMENT);
3776 if (Growable(field))
3778 /* for a growable field we must assume zero terminated strings, because
3779 somehow we have to detect the length of what should be copied.
3781 unsigned int vlen = strlen(value);
3784 if (!Field_Grown(field,
3785 (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
3786 RETURN(E_SYSTEM_ERROR);
3788 /* in this case we also have to check, wether or not the remaining
3789 characters in value are also printable for buffer 0. */
3794 for(i=len; i<vlen; i++)
3795 if (!isprint((unsigned char)value[i]))
3796 RETURN(E_BAD_ARGUMENT);
3802 p = Address_Of_Nth_Buffer(field,buffer);
3805 s = memccpy(p,value,0,len);
3807 for(s=(char *)value; *s && (s < (value+len)); s++)
3809 if (s < (value+len))
3819 { /* this means, value was null terminated and not greater than the
3820 buffer. We have to pad with blanks. Please note that due to memccpy
3821 logic s points after the terminating null. */
3822 s--; /* now we point to the terminator. */
3823 assert(len >= (unsigned int)(s-p));
3824 if (len > (unsigned int)(s-p))
3825 memset(s,C_BLANK,len-(unsigned int)(s-p));
3831 if (((syncres=Synchronize_Field( field ))!=E_OK) &&
3834 if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
3841 /*---------------------------------------------------------------------------
3842 | Facility : libnform
3843 | Function : char *field_buffer(const FIELD *field,int buffer)
3845 | Description : Return the address of the buffer for the field.
3847 | Return Values : Pointer to buffer or NULL if arguments were invalid.
3848 +--------------------------------------------------------------------------*/
3849 NCURSES_EXPORT(char *)
3850 field_buffer (const FIELD * field, int buffer)
3852 if (field && (buffer >= 0) && (buffer <= field->nbuf))
3853 return Address_Of_Nth_Buffer(field,buffer);
3858 /* frm_driver.c ends here */