1 /*-----------------------------------------------------------------------------+
2 | The ncurses form library is Copyright (C) 1995-1997 |
3 | by Juergen Pfeifer <Juergen.Pfeifer@T-Online.de> |
4 | All Rights Reserved. |
6 | Permission to use, copy, modify, and distribute this software and its |
7 | documentation for any purpose and without fee is hereby granted, provided |
8 | that the above copyright notice appear in all copies and that both that |
9 | copyright notice and this permission notice appear in supporting |
10 | documentation, and that the name of the above listed copyright holder(s) not |
11 | be used in advertising or publicity pertaining to distribution of the |
12 | software without specific, written prior permission. |
14 | THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO |
15 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- |
16 | NESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR |
17 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RE- |
18 | SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
19 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH |
20 | THE USE OR PERFORMANCE OF THIS SOFTWARE. |
21 +-----------------------------------------------------------------------------*/
23 /*----------------------------------------------------------------------------
24 This is the core module of the form library. It contains the majority
25 of the driver routines as well as the form_driver function.
27 Essentially this module is nearly the whole library. This is because
28 all the functions in this module depends on some others in the module,
29 so it makes no sense to split them into separate files because they
30 will always be linked together. The only acceptable concern is turnaround
31 time for this module, but now we have all Pentiums or Riscs, so what!
33 The driver routines are grouped into nine generic categories:
35 a) Page Navigation ( all functions prefixed by PN_ )
36 The current page of the form is left and some new page is
38 b) Inter-Field Navigation ( all functions prefixed by FN_ )
39 The current field of the form is left and some new field is
41 c) Intra-Field Navigation ( all functions prefixed by IFN_ )
42 The current position in the current field is changed.
43 d) Vertical Scrolling ( all functions prefixed by VSC_ )
44 Esseantially this is a specialization of Intra-Field navigation.
45 It has to check for a multi-line field.
46 e) Horizontal Scrolling ( all functions prefixed by HSC_ )
47 Esseantially this is a specialization of Intra-Field navigation.
48 It has to check for a single-line field.
49 f) Field Editing ( all functions prefixed by FE_ )
50 The content of the current field is changed
51 g) Edit Mode requests ( all functions prefixed by EM_ )
52 Switching between insert and overlay mode
53 h) Field-Validation requests ( all functions prefixed by FV_ )
54 Perform verifications of the field.
55 i) Choice requests ( all functions prefixed by CR_ )
56 Requests to enumerate possible field values
57 --------------------------------------------------------------------------*/
59 /*----------------------------------------------------------------------------
60 Some remarks on the placements of assert() macros :
61 I use them only on "strategic" places, i.e. top level entries where
62 I want to make sure that things are set correctly. Throughout subordinate
63 routines I omit them mostly.
64 --------------------------------------------------------------------------*/
66 #include "form.priv.h"
68 MODULE_ID("$Id: frm_driver.c,v 1.20 1997/05/01 16:47:54 juergen Exp $")
71 Some options that may effect compatibility in behavior to SVr4 forms,
72 but they are here to allow a more intuitive and user friendly behaviour of
73 our form implementation. This doesn't affect the API, so we feel it is
76 The initial implementation tries to stay very close with the behaviour
77 of the original SVr4 implementation, although in some areas it is quite
78 clear that this isn't the most appropriate way. As far as possible this
79 sources will allow you to build a forms lib that behaves quite similar
80 to SVr4, but now and in the future we will give you better options.
81 Perhaps at some time we will make this configurable at runtime.
84 /* Implement a more user-friendly previous/next word behaviour */
85 #define FRIENDLY_PREV_NEXT_WORD (1)
86 /* Fix the wrong behaviour for forms with all fields inactive */
87 #define FIX_FORM_INACTIVE_BUG (1)
89 /*----------------------------------------------------------------------------
90 Forward references to some internally used static functions
91 --------------------------------------------------------------------------*/
92 static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
93 static int FN_Next_Field (FORM * form);
94 static int FN_Previous_Field (FORM * form);
95 static int FE_New_Line(FORM *);
96 static int FE_Delete_Previous(FORM *);
98 /*----------------------------------------------------------------------------
101 Some Remarks on that: I use the convention to use UPPERCASE for constants
102 defined by Macros. If I provide a macro as a kind of inline routine to
103 provide some logic, I use my Upper_Lower case style.
104 --------------------------------------------------------------------------*/
106 /* Calculate the position of a single row in a field buffer */
107 #define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
109 /* Calculate start address for the fields buffer# N */
110 #define Address_Of_Nth_Buffer(field,N) \
111 ((field)->buf + (N)*(1+Buffer_Length(field)))
113 /* Calculate the start address of the row in the fields specified buffer# N */
114 #define Address_Of_Row_In_Nth_Buffer(field,N,row) \
115 (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
117 /* Calculate the start address of the row in the fields primary buffer */
118 #define Address_Of_Row_In_Buffer(field,row) \
119 Address_Of_Row_In_Nth_Buffer(field,0,row)
121 /* Calculate the start address of the row in the forms current field
123 #define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
124 Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
126 /* Calculate the start address of the row in the forms current field
128 #define Address_Of_Current_Row_In_Buffer(form) \
129 Address_Of_Current_Row_In_Nth_Buffer(form,0)
131 /* Calculate the address of the cursor in the forms current field
133 #define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
134 (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
136 /* Calculate the address of the cursor in the forms current field
138 #define Address_Of_Current_Position_In_Buffer(form) \
139 Address_Of_Current_Position_In_Nth_Buffer(form,0)
141 /* Logic to decide wether or not a field is actually a field with
142 vertical or horizontal scrolling */
143 #define Is_Scroll_Field(field) \
144 (((field)->drows > (field)->rows) || \
145 ((field)->dcols > (field)->cols))
147 /* Logic to decide whether or not a field needs to have an individual window
148 instead of a derived window because it contains invisible parts.
149 This is true for non-public fields and for scrollable fields. */
150 #define Has_Invisible_Parts(field) \
151 (!((field)->opts & O_PUBLIC) || \
152 Is_Scroll_Field(field))
154 /* Logic to decide whether or not a field needs justification */
155 #define Justification_Allowed(field) \
156 (((field)->just != NO_JUSTIFICATION) && \
157 (Single_Line_Field(field)) && \
158 (((field)->dcols == (field)->cols) && \
159 ((field)->opts & O_STATIC)) )
161 /* Logic to determine whether or not a dynamic field may still grow */
162 #define Growable(field) ((field)->status & _MAY_GROW)
164 /* Macro to set the attributes for a fields window */
165 #define Set_Field_Window_Attributes(field,win) \
167 wbkgdset((win),(chtype)((field)->pad | (field)->back)); \
168 wattrset((win),(field)->fore); \
171 /* Logic to decide whether or not a field really appears on the form */
172 #define Field_Really_Appears(field) \
174 (field->form->status & _POSTED) &&\
175 (field->opts & O_VISIBLE) &&\
176 (field->page == field->form->curpage))
178 /* Logic to determine whether or not we are on the first position in the
180 #define First_Position_In_Current_Field(form) \
181 (((form)->currow==0) && ((form)->curcol==0))
183 /* This are the field options required to be a selectable field in field
184 navigation requests */
185 #define O_SELECTABLE (O_ACTIVE | O_VISIBLE)
187 /* Logic to determine whether or not a field is selectable */
188 #define Field_Is_Selectable(f) (((f)->opts & O_SELECTABLE)==O_SELECTABLE)
189 #define Field_Is_Not_Selectable(f) (((f)->opts & O_SELECTABLE)!=O_SELECTABLE)
191 #define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
192 #define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
194 /*---------------------------------------------------------------------------
195 | Facility : libnform
196 | Function : static char *Get_Start_Of_Data(char * buf, int blen)
198 | Description : Return pointer to first non-blank position in buffer.
199 | If buffer is empty return pointer to buffer itself.
201 | Return Values : Pointer to first non-blank position in buffer
202 +--------------------------------------------------------------------------*/
203 INLINE static char *Get_Start_Of_Data(char * buf, int blen)
206 char *end = &buf[blen];
208 assert(buf && blen>=0);
209 while( (p < end) && is_blank(*p) )
211 return( (p==end) ? buf : p );
214 /*---------------------------------------------------------------------------
215 | Facility : libnform
216 | Function : static char *After_End_Of_Data(char * buf, int blen)
218 | Description : Return pointer after last non-blank position in buffer.
219 | If buffer is empty, return pointer to buffer itself.
221 | Return Values : Pointer to position after last non-blank position in
223 +--------------------------------------------------------------------------*/
224 INLINE static char *After_End_Of_Data(char * buf,int blen)
226 char *p = &buf[blen];
228 assert(buf && blen>=0);
229 while( (p>buf) && is_blank(p[-1]) )
234 /*---------------------------------------------------------------------------
235 | Facility : libnform
236 | Function : static char *Get_First_Whitespace_Character(
237 | char * buf, int blen)
239 | Description : Position to the first whitespace character.
241 | Return Values : Pointer to first whitespace character in buffer.
242 +--------------------------------------------------------------------------*/
243 INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
246 char *end = &p[blen];
248 assert(buf && blen>=0);
249 while( (p < end) && !is_blank(*p))
251 return( (p==end) ? buf : p );
254 /*---------------------------------------------------------------------------
255 | Facility : libnform
256 | Function : static char *After_Last_Whitespace_Character(
257 | char * buf, int blen)
259 | Description : Get the position after the last whitespace character.
261 | Return Values : Pointer to position after last whitespace character in
263 +--------------------------------------------------------------------------*/
264 INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
266 char *p = &buf[blen];
268 assert(buf && blen>=0);
269 while( (p>buf) && !is_blank(p[-1]) )
274 /* Set this to 1 to use the div_t version. This is a good idea if your
275 compiler has an intrinsic div() support. Unfortunately GNU-C has it
277 N.B.: This only works if form->curcol follows immediately form->currow
278 and both are of type int.
280 #define USE_DIV_T (0)
282 /*---------------------------------------------------------------------------
283 | Facility : libnform
284 | Function : static void Adjust_Cursor_Position(
285 | FORM * form, const char * pos)
287 | Description : Set current row and column of the form to values
288 | corresponding to the buffer position.
291 +--------------------------------------------------------------------------*/
292 INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
297 field = form->current;
298 assert( pos >= field->buf && field->dcols > 0);
299 idx = (int)( pos - field->buf );
301 *((div_t *)&(form->currow)) = div(idx,field->dcols);
303 form->currow = idx / field->dcols;
304 form->curcol = idx - field->cols * form->currow;
306 if ( field->drows < form->currow )
310 /*---------------------------------------------------------------------------
311 | Facility : libnform
312 | Function : static void Buffer_To_Window(
313 | const FIELD * field,
316 | Description : Copy the buffer to the window. If its a multiline
317 | field, the buffer is split to the lines of the
318 | window without any editing.
321 +--------------------------------------------------------------------------*/
322 static void Buffer_To_Window(const FIELD * field, WINDOW * win)
329 assert(win && field);
331 width = getmaxx(win);
332 height = getmaxy(win);
334 for(row=0, pBuffer=field->buf;
336 row++, pBuffer += width )
338 if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
340 wmove( win, row, 0 );
341 waddnstr( win, pBuffer, len );
346 /*---------------------------------------------------------------------------
347 | Facility : libnform
348 | Function : static void Window_To_Buffer(
352 | Description : Copy the content of the window into the buffer.
353 | The multiple lines of a window are simply
354 | concatenated into the buffer. Pad characters in
355 | the window will be replaced by blanks in the buffer.
358 +--------------------------------------------------------------------------*/
359 static void Window_To_Buffer(WINDOW * win, FIELD * field)
366 assert(win && field && field->buf );
370 height = getmaxy(win);
372 for(row=0; (row < height) && (row < field->drows); row++ )
374 wmove( win, row, 0 );
375 len += winnstr( win, p+len, field->dcols );
379 /* replace visual padding character by blanks in buffer */
383 for(i=0; i<len; i++, p++)
391 /*---------------------------------------------------------------------------
392 | Facility : libnform
393 | Function : static void Synchronize_Buffer(FORM * form)
395 | Description : If there was a change, copy the content of the
396 | window into the buffer, so the buffer is synchronized
397 | with the windows content. We have to indicate that the
398 | buffer needs validation due to the change.
401 +--------------------------------------------------------------------------*/
402 INLINE static void Synchronize_Buffer(FORM * form)
404 if (form->status & _WINDOW_MODIFIED)
406 form->status &= ~_WINDOW_MODIFIED;
407 form->status |= _FCHECK_REQUIRED;
408 Window_To_Buffer(form->w,form->current);
409 wmove(form->w,form->currow,form->curcol);
413 /*---------------------------------------------------------------------------
414 | Facility : libnform
415 | Function : static bool Field_Grown( FIELD *field, int amount)
417 | Description : This function is called for growable dynamic fields
418 | only. It has to increase the buffers and to allocate
419 | a new window for this field.
420 | This function has the side effect to set a new
421 | field-buffer pointer, the dcols and drows values
422 | as well as a new current Window for the field.
424 | Return Values : TRUE - field successfully increased
425 | FALSE - there was some error
426 +--------------------------------------------------------------------------*/
427 static bool Field_Grown(FIELD * field, int amount)
431 if (field && Growable(field))
433 bool single_line_field = Single_Line_Field(field);
434 int old_buflen = Buffer_Length(field);
436 int old_dcols = field->dcols;
437 int old_drows = field->drows;
438 char *oldbuf = field->buf;
442 FORM *form = field->form;
443 bool need_visual_update = ((form != (FORM *)0) &&
444 (form->status & _POSTED) &&
445 (form->current==field));
447 if (need_visual_update)
448 Synchronize_Buffer(form);
450 if (single_line_field)
452 growth = field->cols * amount;
454 growth = Minimum(field->maxgrow - field->dcols,growth);
455 field->dcols += growth;
456 if (field->dcols == field->maxgrow)
457 field->status &= ~_MAY_GROW;
461 growth = (field->rows + field->nrow) * amount;
463 growth = Minimum(field->maxgrow - field->drows,growth);
464 field->drows += growth;
465 if (field->drows == field->maxgrow)
466 field->status &= ~_MAY_GROW;
468 /* drows, dcols changed, so we get really the new buffer length */
469 new_buflen = Buffer_Length(field);
470 newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
472 { /* restore to previous state */
473 field->dcols = old_dcols;
474 field->drows = old_drows;
475 if (( single_line_field && (field->dcols!=field->maxgrow)) ||
476 (!single_line_field && (field->drows!=field->maxgrow)))
477 field->status |= _MAY_GROW;
481 { /* Copy all the buffers. This is the reason why we can't
489 for(i=0;i<=field->nbuf;i++)
491 new_bp = Address_Of_Nth_Buffer(field,i);
492 old_bp = oldbuf + i*(1+old_buflen);
493 memcpy(new_bp,old_bp,(size_t)old_buflen);
494 if (new_buflen > old_buflen)
495 memset(new_bp + old_buflen,C_BLANK,
496 (size_t)(new_buflen - old_buflen));
497 *(new_bp + new_buflen) = '\0';
500 if (need_visual_update)
502 WINDOW *new_window = newpad(field->drows,field->dcols);
504 { /* restore old state */
505 field->dcols = old_dcols;
506 field->drows = old_drows;
508 if (( single_line_field &&
509 (field->dcols!=field->maxgrow)) ||
510 (!single_line_field &&
511 (field->drows!=field->maxgrow)))
512 field->status |= _MAY_GROW;
516 assert(form!=(FORM *)0);
518 form->w = new_window;
519 Set_Field_Window_Attributes(field,form->w);
521 Buffer_To_Window(field,form->w);
523 wmove(form->w,form->currow,form->curcol);
527 /* reflect changes in linked fields */
528 if (field != field->link)
531 for(linked_field = field->link;
532 linked_field!= field;
533 linked_field = linked_field->link)
535 linked_field->buf = field->buf;
536 linked_field->drows = field->drows;
537 linked_field->dcols = field->dcols;
546 /*---------------------------------------------------------------------------
547 | Facility : libnform
548 | Function : static int Position_Form_Cursor(FORM * form)
550 | Description : Position the currsor in the window for the current
551 | field to be in sync. with the currow and curcol
554 | Return Values : E_OK - success
555 | E_BAD_ARGUMENT - invalid form pointer
556 | E_SYSTEM_ERROR - form has no current field or
558 +--------------------------------------------------------------------------*/
559 static int Position_Form_Cursor(FORM * form)
565 return(E_BAD_ARGUMENT);
567 if (!form->w || !form->current)
568 return(E_SYSTEM_ERROR);
570 field = form->current;
571 formwin = Get_Form_Window(form);
573 wmove( form->w, form->currow, form->curcol );
574 if ( Has_Invisible_Parts(field) )
576 /* in this case fieldwin isn't derived from formwin, so we have
577 to move the cursor in formwin by hand... */
579 field->frow + form->currow - form->toprow,
580 field->fcol + form->curcol - form->begincol);
588 /*---------------------------------------------------------------------------
589 | Facility : libnform
590 | Function : static int Refresh_Current_Field(FORM * form)
592 | Description : Propagate the changes in the fields window to the
593 | window of the form.
595 | Return Values : E_OK - on success
596 | E_BAD_ARGUMENT - invalid form pointer
597 | E_SYSTEM_ERROR - general error
598 +--------------------------------------------------------------------------*/
599 static int Refresh_Current_Field(FORM * form)
605 RETURN(E_BAD_ARGUMENT);
607 if (!form->w || !form->current)
608 RETURN(E_SYSTEM_ERROR);
610 field = form->current;
611 formwin = Get_Form_Window(form);
613 if (field->opts & O_PUBLIC)
615 if (Is_Scroll_Field(field))
617 /* Again, in this case the fieldwin isn't derived from formwin,
618 so we have to perform a copy operation. */
619 if (Single_Line_Field(field))
620 { /* horizontal scrolling */
621 if (form->curcol < form->begincol)
622 form->begincol = form->curcol;
625 if (form->curcol >= (form->begincol + field->cols))
626 form->begincol = form->curcol - field->cols + 1;
635 field->cols + field->fcol - 1,
639 { /* A multiline, i.e. vertical scrolling field */
640 int row_after_bottom,first_modified_row,first_unmodified_row;
642 if (field->drows > field->rows)
644 row_after_bottom = form->toprow + field->rows;
645 if (form->currow < form->toprow)
647 form->toprow = form->currow;
648 field->status |= _NEWTOP;
650 if (form->currow >= row_after_bottom)
652 form->toprow = form->currow - field->rows + 1;
653 field->status |= _NEWTOP;
655 if (field->status & _NEWTOP)
656 { /* means we have to copy whole range */
657 first_modified_row = form->toprow;
658 first_unmodified_row = first_modified_row + field->rows;
659 field->status &= ~_NEWTOP;
662 { /* we try to optimize : finding the range of touched
664 first_modified_row = form->toprow;
665 while(first_modified_row < row_after_bottom)
667 if (is_linetouched(form->w,first_modified_row))
669 first_modified_row++;
671 first_unmodified_row = first_modified_row;
672 while(first_unmodified_row < row_after_bottom)
674 if (!is_linetouched(form->w,first_unmodified_row))
676 first_unmodified_row++;
682 first_modified_row = form->toprow;
683 first_unmodified_row = first_modified_row + field->rows;
685 if (first_unmodified_row != first_modified_row)
690 field->frow + first_modified_row - form->toprow,
692 field->frow + first_unmodified_row - form->toprow - 1,
693 field->cols + field->fcol - 1,
699 { /* if the field-window is simply a derived window, i.e. contains
700 no invisible parts, the whole thing is trivial
706 return Position_Form_Cursor(form);
709 /*---------------------------------------------------------------------------
710 | Facility : libnform
711 | Function : static void Perform_Justification(
715 | Description : Output field with requested justification
718 +--------------------------------------------------------------------------*/
719 static void Perform_Justification(FIELD * field, WINDOW * win)
725 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
726 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
730 assert(win && (field->drows == 1) && (field->dcols == field->cols));
737 col = (field->cols - len)/2;
740 col = field->cols - len;
747 waddnstr(win,bp,len);
751 /*---------------------------------------------------------------------------
752 | Facility : libnform
753 | Function : static void Undo_Justification(
757 | Description : Display field without any justification, i.e.
761 +--------------------------------------------------------------------------*/
762 static void Undo_Justification(FIELD * field, WINDOW * win)
767 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
768 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
774 waddnstr(win,bp,len);
778 /*---------------------------------------------------------------------------
779 | Facility : libnform
780 | Function : static bool Check_Char(
783 | TypeArgument *argp)
785 | Description : Perform a single character check for character ch
786 | according to the fieldtype instance.
788 | Return Values : TRUE - Character is valid
789 | FALSE - Character is invalid
790 +--------------------------------------------------------------------------*/
791 static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
795 if (typ->status & _LINKED_TYPE)
799 Check_Char(typ->left ,ch,argp->left ) ||
800 Check_Char(typ->right,ch,argp->right) );
805 return typ->ccheck(ch,(void *)argp);
808 return isprint((unsigned char)ch);
811 /*---------------------------------------------------------------------------
812 | Facility : libnform
813 | Function : static int Display_Or_Erase_Field(
817 | Description : Create a subwindow for the field and display the
818 | buffer contents (apply justification if required)
819 | or simply erase the field.
821 | Return Values : E_OK - on success
822 | E_SYSTEM_ERROR - some error (typical no memory)
823 +--------------------------------------------------------------------------*/
824 static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
829 return E_SYSTEM_ERROR;
831 win = derwin(Get_Form_Window(field->form),
832 field->rows,field->cols,field->frow,field->fcol);
835 return E_SYSTEM_ERROR;
838 Set_Field_Window_Attributes(field,win);
844 if (field->opts & O_PUBLIC)
846 if (Justification_Allowed(field))
847 Perform_Justification(field,win);
849 Buffer_To_Window(field,win);
851 field->status &= ~_NEWTOP;
858 /* Macros to preset the bEraseFlag */
859 #define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
860 #define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
862 /*---------------------------------------------------------------------------
863 | Facility : libnform
864 | Function : static int Synchronize_Field(FIELD * field)
866 | Description : Synchronize the windows content with the value in
869 | Return Values : E_OK - success
870 | E_BAD_ARGUMENT - invalid field pointer
871 | E_SYSTEM_ERROR - some severe basic error
872 +--------------------------------------------------------------------------*/
873 static int Synchronize_Field(FIELD * field)
879 return(E_BAD_ARGUMENT);
881 if (((form=field->form) != (FORM *)0)
882 && Field_Really_Appears(field))
884 if (field == form->current)
886 form->currow = form->curcol = form->toprow = form->begincol = 0;
889 if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
890 Undo_Justification( field, form->w );
892 Buffer_To_Window( field, form->w );
894 field->status |= _NEWTOP;
895 res = Refresh_Current_Field( form );
898 res = Display_Field( field );
900 field->status |= _CHANGED;
904 /*---------------------------------------------------------------------------
905 | Facility : libnform
906 | Function : static int Synchronize_Linked_Fields(FIELD * field)
908 | Description : Propagate the Synchronize_Field function to all linked
909 | fields. The first error that occurs in the sequence
910 | of updates is the returnvalue.
912 | Return Values : E_OK - success
913 | E_BAD_ARGUMENT - invalid field pointer
914 | E_SYSTEM_ERROR - some severe basic error
915 +--------------------------------------------------------------------------*/
916 static int Synchronize_Linked_Fields(FIELD * field)
923 return(E_BAD_ARGUMENT);
926 return(E_SYSTEM_ERROR);
928 for(linked_field = field->link;
929 linked_field!= field;
930 linked_field = linked_field->link )
932 if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
939 /*---------------------------------------------------------------------------
940 | Facility : libnform
941 | Function : static int Synchronize_Attributes(FIELD * field)
943 | Description : If a fields visual attributes have changed, this
944 | routine is called to propagate those changes to the
947 | Return Values : E_OK - success
948 | E_BAD_ARGUMENT - invalid field pointer
949 | E_SYSTEM_ERROR - some severe basic error
950 +--------------------------------------------------------------------------*/
951 static int Synchronize_Attributes(FIELD * field)
958 return(E_BAD_ARGUMENT);
960 if (((form=field->form) != (FORM *)0)
961 && Field_Really_Appears(field))
963 if (form->current==field)
965 Synchronize_Buffer(form);
966 Set_Field_Window_Attributes(field,form->w);
968 if (field->opts & O_PUBLIC)
970 if (Justification_Allowed(field))
971 Undo_Justification(field,form->w);
973 Buffer_To_Window(field,form->w);
977 formwin = Get_Form_Window(form);
978 copywin(form->w,formwin,
980 field->frow,field->fcol,
981 field->rows-1,field->cols-1,0);
983 Buffer_To_Window(field,form->w);
984 field->status |= _NEWTOP; /* fake refresh to paint all */
985 Refresh_Current_Field(form);
990 res = Display_Field(field);
996 /*---------------------------------------------------------------------------
997 | Facility : libnform
998 | Function : static int Synchronize_Options(FIELD * field,
999 | Field_Options newopts)
1001 | Description : If a fields options have changed, this routine is
1002 | called to propagate these changes to the screen and
1003 | to really change the behaviour of the field.
1005 | Return Values : E_OK - success
1006 | E_BAD_ARGUMENT - invalid field pointer
1007 | E_SYSTEM_ERROR - some severe basic error
1008 +--------------------------------------------------------------------------*/
1009 static int Synchronize_Options(FIELD *field, Field_Options newopts)
1011 Field_Options oldopts;
1012 Field_Options changed_opts;
1017 return(E_BAD_ARGUMENT);
1019 oldopts = field->opts;
1020 changed_opts = oldopts ^ newopts;
1021 field->opts = newopts;
1026 if (form->current == field)
1028 field->opts = oldopts;
1032 if (form->status & _POSTED)
1034 if ((form->curpage == field->page))
1036 if (changed_opts & O_VISIBLE)
1038 if (newopts & O_VISIBLE)
1039 res = Erase_Field(field);
1041 res = Display_Field(field);
1045 if ((changed_opts & O_PUBLIC) &&
1046 (newopts & O_VISIBLE))
1047 res = Display_Field(field);
1053 if (changed_opts & O_STATIC)
1055 bool single_line_field = Single_Line_Field(field);
1058 if (newopts & O_STATIC)
1059 { /* the field becomes now static */
1060 field->status &= ~_MAY_GROW;
1061 /* if actually we have no hidden columns, justification may
1063 if (single_line_field &&
1064 (field->cols == field->dcols) &&
1065 (field->just != NO_JUSTIFICATION) &&
1066 Field_Really_Appears(field))
1068 res2 = Display_Field(field);
1072 { /* field is no longer static */
1073 if ((field->maxgrow==0) ||
1074 ( single_line_field && (field->dcols < field->maxgrow)) ||
1075 (!single_line_field && (field->drows < field->maxgrow)))
1077 field->status |= _MAY_GROW;
1078 /* a field with justification now changes its behaviour,
1079 so we must redisplay it */
1080 if (single_line_field &&
1081 (field->just != NO_JUSTIFICATION) &&
1082 Field_Really_Appears(field))
1084 res2 = Display_Field(field);
1095 /*---------------------------------------------------------------------------
1096 | Facility : libnform
1097 | Function : static int Set_Current_Field(
1101 | Description : Make the newfield the new current field.
1103 | Return Values : E_OK - success
1104 | E_BAD_ARGUMENT - invalid form or field pointer
1105 | E_SYSTEM_ERROR - some severe basic error
1106 +--------------------------------------------------------------------------*/
1107 static int Set_Current_Field(FORM *form, FIELD *newfield)
1112 if (!form || !newfield || !form->current || (newfield->form!=form))
1113 return(E_BAD_ARGUMENT);
1115 if ( (form->status & _IN_DRIVER) )
1116 return(E_BAD_STATE);
1119 return(E_NOT_CONNECTED);
1121 field = form->current;
1123 if ((field!=newfield) ||
1124 !(form->status & _POSTED))
1127 (field->opts & O_VISIBLE) &&
1128 (field->form->curpage == field->page))
1130 Refresh_Current_Field(form);
1131 if (field->opts & O_PUBLIC)
1133 if (field->drows > field->rows)
1135 if (form->toprow==0)
1136 field->status &= ~_NEWTOP;
1138 field->status |= _NEWTOP;
1142 if (Justification_Allowed(field))
1144 Window_To_Buffer(form->w,field);
1146 Perform_Justification(field,form->w);
1156 if (Has_Invisible_Parts(field))
1157 new_window = newpad(field->drows,field->dcols);
1159 new_window = derwin(Get_Form_Window(form),
1160 field->rows,field->cols,field->frow,field->fcol);
1163 return(E_SYSTEM_ERROR);
1165 form->current = field;
1166 form->w = new_window;
1167 form->status &= ~_WINDOW_MODIFIED;
1168 Set_Field_Window_Attributes(field,form->w);
1170 if (Has_Invisible_Parts(field))
1173 Buffer_To_Window(field,form->w);
1177 if (Justification_Allowed(field))
1180 Undo_Justification(field,form->w);
1185 untouchwin(form->w);
1188 form->currow = form->curcol = form->toprow = form->begincol = 0;
1192 /*----------------------------------------------------------------------------
1193 Intra-Field Navigation routines
1194 --------------------------------------------------------------------------*/
1196 /*---------------------------------------------------------------------------
1197 | Facility : libnform
1198 | Function : static int IFN_Next_Character(FORM * form)
1200 | Description : Move to the next character in the field. In a multiline
1201 | field this wraps and the end of the line.
1203 | Return Values : E_OK - success
1204 | E_REQUEST_DENIED - at the rightmost position
1205 +--------------------------------------------------------------------------*/
1206 static int IFN_Next_Character(FORM * form)
1208 FIELD *field = form->current;
1210 if ((++(form->curcol))==field->dcols)
1212 if ((++(form->currow))==field->drows)
1216 return(E_REQUEST_DENIED);
1223 /*---------------------------------------------------------------------------
1224 | Facility : libnform
1225 | Function : static int IFN_Previous_Character(FORM * form)
1227 | Description : Move to the previous character in the field. In a
1228 | multiline field this wraps and the beginning of the
1231 | Return Values : E_OK - success
1232 | E_REQUEST_DENIED - at the leftmost position
1233 +--------------------------------------------------------------------------*/
1234 static int IFN_Previous_Character(FORM * form)
1236 if ((--(form->curcol))<0)
1238 if ((--(form->currow))<0)
1242 return(E_REQUEST_DENIED);
1244 form->curcol = form->current->dcols - 1;
1249 /*---------------------------------------------------------------------------
1250 | Facility : libnform
1251 | Function : static int IFN_Next_Line(FORM * form)
1253 | Description : Move to the beginning of the next line in the field
1255 | Return Values : E_OK - success
1256 | E_REQUEST_DENIED - at the last line
1257 +--------------------------------------------------------------------------*/
1258 static int IFN_Next_Line(FORM * form)
1260 FIELD *field = form->current;
1262 if ((++(form->currow))==field->drows)
1265 return(E_REQUEST_DENIED);
1271 /*---------------------------------------------------------------------------
1272 | Facility : libnform
1273 | Function : static int IFN_Previous_Line(FORM * form)
1275 | Description : Move to the beginning of the previous line in the field
1277 | Return Values : E_OK - success
1278 | E_REQUEST_DENIED - at the first line
1279 +--------------------------------------------------------------------------*/
1280 static int IFN_Previous_Line(FORM * form)
1282 if ( (--(form->currow)) < 0 )
1285 return(E_REQUEST_DENIED);
1291 /*---------------------------------------------------------------------------
1292 | Facility : libnform
1293 | Function : static int IFN_Next_Word(FORM * form)
1295 | Description : Move to the beginning of the next word in the field.
1297 | Return Values : E_OK - success
1298 | E_REQUEST_DENIED - there is no next word
1299 +--------------------------------------------------------------------------*/
1300 static int IFN_Next_Word(FORM * form)
1302 FIELD *field = form->current;
1303 char *bp = Address_Of_Current_Position_In_Buffer(form);
1307 /* We really need access to the data, so we have to synchronize */
1308 Synchronize_Buffer(form);
1310 /* Go to the first whitespace after the current position (including
1311 current position). This is then the startpoint to look for the
1312 next non-blank data */
1313 s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
1314 (int)(bp - field->buf));
1316 /* Find the start of the next word */
1317 t = Get_Start_Of_Data(s,Buffer_Length(field) -
1318 (int)(s - field->buf));
1319 #if !FRIENDLY_PREV_NEXT_WORD
1321 return(E_REQUEST_DENIED);
1325 Adjust_Cursor_Position(form,t);
1330 /*---------------------------------------------------------------------------
1331 | Facility : libnform
1332 | Function : static int IFN_Previous_Word(FORM * form)
1334 | Description : Move to the beginning of the previous word in the field.
1336 | Return Values : E_OK - success
1337 | E_REQUEST_DENIED - there is no previous word
1338 +--------------------------------------------------------------------------*/
1339 static int IFN_Previous_Word(FORM * form)
1341 FIELD *field = form->current;
1342 char *bp = Address_Of_Current_Position_In_Buffer(form);
1347 /* We really need access to the data, so we have to synchronize */
1348 Synchronize_Buffer(form);
1350 s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
1351 /* s points now right after the last non-blank in the buffer before bp.
1352 If bp was in a word, s equals bp. In this case we must find the last
1353 whitespace in the buffer before bp and repeat the game to really find
1354 the previous word! */
1358 /* And next call now goes backward to look for the last whitespace
1359 before that, pointing right after this, so it points to the begin
1360 of the previous word.
1362 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1363 #if !FRIENDLY_PREV_NEXT_WORD
1365 return(E_REQUEST_DENIED);
1368 { /* and do it again, replacing bp by t */
1369 s = After_End_Of_Data(field->buf,(int)(t - field->buf));
1370 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1371 #if !FRIENDLY_PREV_NEXT_WORD
1373 return(E_REQUEST_DENIED);
1376 Adjust_Cursor_Position(form,t);
1380 /*---------------------------------------------------------------------------
1381 | Facility : libnform
1382 | Function : static int IFN_Beginning_Of_Field(FORM * form)
1384 | Description : Place the cursor at the first non-pad character in
1387 | Return Values : E_OK - success
1388 +--------------------------------------------------------------------------*/
1389 static int IFN_Beginning_Of_Field(FORM * form)
1391 FIELD *field = form->current;
1393 Synchronize_Buffer(form);
1394 Adjust_Cursor_Position(form,
1395 Get_Start_Of_Data(field->buf,Buffer_Length(field)));
1399 /*---------------------------------------------------------------------------
1400 | Facility : libnform
1401 | Function : static int IFN_End_Of_Field(FORM * form)
1403 | Description : Place the cursor after the last non-pad character in
1404 | the field. If the field occupies the last position in
1405 | the buffer, the cursos is positioned on the last
1408 | Return Values : E_OK - success
1409 +--------------------------------------------------------------------------*/
1410 static int IFN_End_Of_Field(FORM * form)
1412 FIELD *field = form->current;
1415 Synchronize_Buffer(form);
1416 pos = After_End_Of_Data(field->buf,Buffer_Length(field));
1417 if (pos==(field->buf + Buffer_Length(field)))
1419 Adjust_Cursor_Position(form,pos);
1423 /*---------------------------------------------------------------------------
1424 | Facility : libnform
1425 | Function : static int IFN_Beginning_Of_Line(FORM * form)
1427 | Description : Place the cursor on the first non-pad character in
1428 | the current line of the field.
1430 | Return Values : E_OK - success
1431 +--------------------------------------------------------------------------*/
1432 static int IFN_Beginning_Of_Line(FORM * form)
1434 FIELD *field = form->current;
1436 Synchronize_Buffer(form);
1437 Adjust_Cursor_Position(form,
1438 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1443 /*---------------------------------------------------------------------------
1444 | Facility : libnform
1445 | Function : static int IFN_End_Of_Line(FORM * form)
1447 | Description : Place the cursor after the last non-pad character in the
1448 | current line of the field. If the field occupies the
1449 | last column in the line, the cursor is positioned on the
1450 | last character of the line.
1452 | Return Values : E_OK - success
1453 +--------------------------------------------------------------------------*/
1454 static int IFN_End_Of_Line(FORM * form)
1456 FIELD *field = form->current;
1460 Synchronize_Buffer(form);
1461 bp = Address_Of_Current_Row_In_Buffer(form);
1462 pos = After_End_Of_Data(bp,field->dcols);
1463 if (pos == (bp + field->dcols))
1465 Adjust_Cursor_Position(form,pos);
1469 /*---------------------------------------------------------------------------
1470 | Facility : libnform
1471 | Function : static int IFN_Left_Character(FORM * form)
1473 | Description : Move one character to the left in the current line.
1474 | This doesn't cycle.
1476 | Return Values : E_OK - success
1477 | E_REQUEST_DENIED - already in first column
1478 +--------------------------------------------------------------------------*/
1479 static int IFN_Left_Character(FORM * form)
1481 if ( (--(form->curcol)) < 0 )
1484 return(E_REQUEST_DENIED);
1489 /*---------------------------------------------------------------------------
1490 | Facility : libnform
1491 | Function : static int IFN_Right_Character(FORM * form)
1493 | Description : Move one character to the right in the current line.
1494 | This doesn't cycle.
1496 | Return Values : E_OK - success
1497 | E_REQUEST_DENIED - already in last column
1498 +--------------------------------------------------------------------------*/
1499 static int IFN_Right_Character(FORM * form)
1501 if ( (++(form->curcol)) == form->current->dcols )
1504 return(E_REQUEST_DENIED);
1509 /*---------------------------------------------------------------------------
1510 | Facility : libnform
1511 | Function : static int IFN_Up_Character(FORM * form)
1513 | Description : Move one line up. This doesn't cycle through the lines
1516 | Return Values : E_OK - success
1517 | E_REQUEST_DENIED - already in last column
1518 +--------------------------------------------------------------------------*/
1519 static int IFN_Up_Character(FORM * form)
1521 if ( (--(form->currow)) < 0 )
1524 return(E_REQUEST_DENIED);
1529 /*---------------------------------------------------------------------------
1530 | Facility : libnform
1531 | Function : static int IFN_Down_Character(FORM * form)
1533 | Description : Move one line down. This doesn't cycle through the
1534 | lines of the field.
1536 | Return Values : E_OK - success
1537 | E_REQUEST_DENIED - already in last column
1538 +--------------------------------------------------------------------------*/
1539 static int IFN_Down_Character(FORM * form)
1541 FIELD *field = form->current;
1543 if ( (++(form->currow)) == field->drows )
1546 return(E_REQUEST_DENIED);
1550 /*----------------------------------------------------------------------------
1551 END of Intra-Field Navigation routines
1552 --------------------------------------------------------------------------*/
1554 /*----------------------------------------------------------------------------
1555 Vertical scrolling helper routines
1556 --------------------------------------------------------------------------*/
1558 /*---------------------------------------------------------------------------
1559 | Facility : libnform
1560 | Function : static int VSC_Generic(FORM *form, int lines)
1562 | Description : Scroll multi-line field forward (lines>0) or
1563 | backward (lines<0) this many lines.
1565 | Return Values : E_OK - success
1566 | E_REQUEST_DENIED - can't scroll
1567 +--------------------------------------------------------------------------*/
1568 static int VSC_Generic(FORM *form, int lines)
1570 FIELD *field = form->current;
1571 int res = E_REQUEST_DENIED;
1572 int rows_to_go = (lines > 0 ? lines : -lines);
1576 if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
1577 rows_to_go = (field->drows - field->rows - form->toprow);
1581 form->currow += rows_to_go;
1582 form->toprow += rows_to_go;
1588 if (rows_to_go > form->toprow)
1589 rows_to_go = form->toprow;
1593 form->currow -= rows_to_go;
1594 form->toprow -= rows_to_go;
1600 /*----------------------------------------------------------------------------
1601 End of Vertical scrolling helper routines
1602 --------------------------------------------------------------------------*/
1604 /*----------------------------------------------------------------------------
1605 Vertical scrolling routines
1606 --------------------------------------------------------------------------*/
1608 /*---------------------------------------------------------------------------
1609 | Facility : libnform
1610 | Function : static int Vertical_Scrolling(
1611 | int (* const fct) (FORM *),
1614 | Description : Performs the generic vertical scrolling routines.
1615 | This has to check for a multi-line field and to set
1616 | the _NEWTOP flag if scrolling really occured.
1618 | Return Values : Propagated error code from low-level driver calls
1619 +--------------------------------------------------------------------------*/
1620 static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
1622 int res = E_REQUEST_DENIED;
1624 if (!Single_Line_Field(form->current))
1628 form->current->status |= _NEWTOP;
1633 /*---------------------------------------------------------------------------
1634 | Facility : libnform
1635 | Function : static int VSC_Scroll_Line_Forward(FORM * form)
1637 | Description : Scroll multi-line field forward a line
1639 | Return Values : E_OK - success
1640 | E_REQUEST_DENIED - no data ahead
1641 +--------------------------------------------------------------------------*/
1642 static int VSC_Scroll_Line_Forward(FORM * form)
1644 return VSC_Generic(form,1);
1647 /*---------------------------------------------------------------------------
1648 | Facility : libnform
1649 | Function : static int VSC_Scroll_Line_Backward(FORM * form)
1651 | Description : Scroll multi-line field backward a line
1653 | Return Values : E_OK - success
1654 | E_REQUEST_DENIED - no data behind
1655 +--------------------------------------------------------------------------*/
1656 static int VSC_Scroll_Line_Backward(FORM * form)
1658 return VSC_Generic(form,-1);
1661 /*---------------------------------------------------------------------------
1662 | Facility : libnform
1663 | Function : static int VSC_Scroll_Page_Forward(FORM * form)
1665 | Description : Scroll a multi-line field forward a page
1667 | Return Values : E_OK - success
1668 | E_REQUEST_DENIED - no data ahead
1669 +--------------------------------------------------------------------------*/
1670 static int VSC_Scroll_Page_Forward(FORM * form)
1672 return VSC_Generic(form,form->current->rows);
1675 /*---------------------------------------------------------------------------
1676 | Facility : libnform
1677 | Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1679 | Description : Scroll a multi-line field forward half a page
1681 | Return Values : E_OK - success
1682 | E_REQUEST_DENIED - no data ahead
1683 +--------------------------------------------------------------------------*/
1684 static int VSC_Scroll_Half_Page_Forward(FORM * form)
1686 return VSC_Generic(form,(form->current->rows + 1)/2);
1689 /*---------------------------------------------------------------------------
1690 | Facility : libnform
1691 | Function : static int VSC_Scroll_Page_Backward(FORM * form)
1693 | Description : Scroll a multi-line field backward a page
1695 | Return Values : E_OK - success
1696 | E_REQUEST_DENIED - no data behind
1697 +--------------------------------------------------------------------------*/
1698 static int VSC_Scroll_Page_Backward(FORM * form)
1700 return VSC_Generic(form, -(form->current->rows));
1703 /*---------------------------------------------------------------------------
1704 | Facility : libnform
1705 | Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
1707 | Description : Scroll a multi-line field backward half a page
1709 | Return Values : E_OK - success
1710 | E_REQUEST_DENIED - no data behind
1711 +--------------------------------------------------------------------------*/
1712 static int VSC_Scroll_Half_Page_Backward(FORM * form)
1714 return VSC_Generic(form, -((form->current->rows + 1)/2));
1716 /*----------------------------------------------------------------------------
1717 End of Vertical scrolling routines
1718 --------------------------------------------------------------------------*/
1720 /*----------------------------------------------------------------------------
1721 Horizontal scrolling helper routines
1722 --------------------------------------------------------------------------*/
1724 /*---------------------------------------------------------------------------
1725 | Facility : libnform
1726 | Function : static int HSC_Generic(FORM *form, int columns)
1728 | Description : Scroll single-line field forward (columns>0) or
1729 | backward (columns<0) this many columns.
1731 | Return Values : E_OK - success
1732 | E_REQUEST_DENIED - can't scroll
1733 +--------------------------------------------------------------------------*/
1734 static int HSC_Generic(FORM *form, int columns)
1736 FIELD *field = form->current;
1737 int res = E_REQUEST_DENIED;
1738 int cols_to_go = (columns > 0 ? columns : -columns);
1742 if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
1743 cols_to_go = field->dcols - field->cols - form->begincol;
1747 form->curcol += cols_to_go;
1748 form->begincol += cols_to_go;
1754 if ( cols_to_go > form->begincol )
1755 cols_to_go = form->begincol;
1759 form->curcol -= cols_to_go;
1760 form->begincol -= cols_to_go;
1766 /*----------------------------------------------------------------------------
1767 End of Horizontal scrolling helper routines
1768 --------------------------------------------------------------------------*/
1770 /*----------------------------------------------------------------------------
1771 Horizontal scrolling routines
1772 --------------------------------------------------------------------------*/
1774 /*---------------------------------------------------------------------------
1775 | Facility : libnform
1776 | Function : static int Horizontal_Scrolling(
1777 | int (* const fct) (FORM *),
1780 | Description : Performs the generic horizontal scrolling routines.
1781 | This has to check for a single-line field.
1783 | Return Values : Propagated error code from low-level driver calls
1784 +--------------------------------------------------------------------------*/
1785 static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
1787 if (Single_Line_Field(form->current))
1790 return(E_REQUEST_DENIED);
1793 /*---------------------------------------------------------------------------
1794 | Facility : libnform
1795 | Function : static int HSC_Scroll_Char_Forward(FORM * form)
1797 | Description : Scroll single-line field forward a character
1799 | Return Values : E_OK - success
1800 | E_REQUEST_DENIED - no data ahead
1801 +--------------------------------------------------------------------------*/
1802 static int HSC_Scroll_Char_Forward(FORM *form)
1804 return HSC_Generic(form,1);
1807 /*---------------------------------------------------------------------------
1808 | Facility : libnform
1809 | Function : static int HSC_Scroll_Char_Backward(FORM * form)
1811 | Description : Scroll single-line field backward a character
1813 | Return Values : E_OK - success
1814 | E_REQUEST_DENIED - no data behind
1815 +--------------------------------------------------------------------------*/
1816 static int HSC_Scroll_Char_Backward(FORM *form)
1818 return HSC_Generic(form,-1);
1821 /*---------------------------------------------------------------------------
1822 | Facility : libnform
1823 | Function : static int HSC_Horizontal_Line_Forward(FORM* form)
1825 | Description : Scroll single-line field forward a line
1827 | Return Values : E_OK - success
1828 | E_REQUEST_DENIED - no data ahead
1829 +--------------------------------------------------------------------------*/
1830 static int HSC_Horizontal_Line_Forward(FORM * form)
1832 return HSC_Generic(form,form->current->cols);
1835 /*---------------------------------------------------------------------------
1836 | Facility : libnform
1837 | Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
1839 | Description : Scroll single-line field forward half a line
1841 | Return Values : E_OK - success
1842 | E_REQUEST_DENIED - no data ahead
1843 +--------------------------------------------------------------------------*/
1844 static int HSC_Horizontal_Half_Line_Forward(FORM * form)
1846 return HSC_Generic(form,(form->current->cols + 1)/2);
1849 /*---------------------------------------------------------------------------
1850 | Facility : libnform
1851 | Function : static int HSC_Horizontal_Line_Backward(FORM* form)
1853 | Description : Scroll single-line field backward a line
1855 | Return Values : E_OK - success
1856 | E_REQUEST_DENIED - no data behind
1857 +--------------------------------------------------------------------------*/
1858 static int HSC_Horizontal_Line_Backward(FORM * form)
1860 return HSC_Generic(form,-(form->current->cols));
1863 /*---------------------------------------------------------------------------
1864 | Facility : libnform
1865 | Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
1867 | Description : Scroll single-line field backward half a line
1869 | Return Values : E_OK - success
1870 | E_REQUEST_DENIED - no data behind
1871 +--------------------------------------------------------------------------*/
1872 static int HSC_Horizontal_Half_Line_Backward(FORM * form)
1874 return HSC_Generic(form,-((form->current->cols + 1)/2));
1877 /*----------------------------------------------------------------------------
1878 End of Horizontal scrolling routines
1879 --------------------------------------------------------------------------*/
1881 /*----------------------------------------------------------------------------
1882 Helper routines for Field Editing
1883 --------------------------------------------------------------------------*/
1885 /*---------------------------------------------------------------------------
1886 | Facility : libnform
1887 | Function : static bool Is_There_Room_For_A_Line(FORM * form)
1889 | Description : Check whether or not there is enough room in the
1890 | buffer to enter a whole line.
1892 | Return Values : TRUE - there is enough space
1893 | FALSE - there is not enough space
1894 +--------------------------------------------------------------------------*/
1895 INLINE static bool Is_There_Room_For_A_Line(FORM * form)
1897 FIELD *field = form->current;
1898 char *begin_of_last_line, *s;
1900 Synchronize_Buffer(form);
1901 begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
1902 s = After_End_Of_Data(begin_of_last_line,field->dcols);
1903 return ((s==begin_of_last_line) ? TRUE : FALSE);
1906 /*---------------------------------------------------------------------------
1907 | Facility : libnform
1908 | Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1910 | Description : Checks whether or not there is room for a new character
1911 | in the current line.
1913 | Return Values : TRUE - there is room
1914 | FALSE - there is not enough room (line full)
1915 +--------------------------------------------------------------------------*/
1916 INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1918 int last_char_in_line;
1920 wmove(form->w,form->currow,form->current->dcols-1);
1921 last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
1922 wmove(form->w,form->currow,form->curcol);
1923 return (((last_char_in_line == form->current->pad) ||
1924 is_blank(last_char_in_line)) ? TRUE : FALSE);
1927 #define There_Is_No_Room_For_A_Char_In_Line(f) \
1928 !Is_There_Room_For_A_Char_In_Line(f)
1930 /*---------------------------------------------------------------------------
1931 | Facility : libnform
1932 | Function : static int Insert_String(
1938 | Description : Insert the 'len' characters beginning at pointer 'txt'
1939 | into the 'row' of the 'form'. The insertion occurs
1940 | on the beginning of the row, all other characters are
1941 | moved to the right. After the text a pad character will
1942 | be inserted to separate the text from the rest. If
1943 | necessary the insertion moves characters on the next
1944 | line to make place for the requested insertion string.
1946 | Return Values : E_OK - success
1947 | E_REQUEST_DENIED -
1948 | E_SYSTEM_ERROR - system error
1949 +--------------------------------------------------------------------------*/
1950 static int Insert_String(FORM *form, int row, char *txt, int len)
1952 FIELD *field = form->current;
1953 char *bp = Address_Of_Row_In_Buffer(field,row);
1954 int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
1955 int freelen = field->dcols - datalen;
1956 int requiredlen = len+1;
1958 int result = E_REQUEST_DENIED;
1959 const char *Space = " ";
1961 if (freelen >= requiredlen)
1963 wmove(form->w,row,0);
1964 winsnstr(form->w,txt,len);
1965 wmove(form->w,row,len);
1966 winsnstr(form->w,Space,1);
1970 { /* we have to move characters on the next line. If we are on the
1971 last line this may work, if the field is growable */
1972 if ((row == (field->drows - 1)) && Growable(field))
1974 if (!Field_Grown(field,1))
1975 return(E_SYSTEM_ERROR);
1976 /* !!!Side-Effect : might be changed due to growth!!! */
1977 bp = Address_Of_Row_In_Buffer(field,row);
1980 if (row < (field->drows - 1))
1982 split = After_Last_Whitespace_Character(bp,
1983 (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
1984 requiredlen) - bp));
1985 /* split points now to the first character of the portion of the
1986 line that must be moved to the next line */
1987 datalen = (int)(split-bp); /* + freelen has to stay on this line */
1988 freelen = field->dcols - (datalen + freelen); /* for the next line */
1990 if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
1992 wmove(form->w,row,datalen);
1994 wmove(form->w,row,0);
1995 winsnstr(form->w,txt,len);
1996 wmove(form->w,row,len);
1997 winsnstr(form->w,Space,1);
2005 /*---------------------------------------------------------------------------
2006 | Facility : libnform
2007 | Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2010 | Description : If a character has been entered into a field, it may
2011 | be that wrapping has to occur. This routine checks
2012 | whether or not wrapping is required and if so, performs
2015 | Return Values : E_OK - no wrapping required or wrapping
2017 | E_REQUEST_DENIED -
2018 | E_SYSTEM_ERROR - some system error
2019 +--------------------------------------------------------------------------*/
2020 static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
2022 FIELD *field = form->current;
2023 int result = E_REQUEST_DENIED;
2024 bool Last_Row = ((field->drows - 1) == form->currow);
2026 if ( (field->opts & O_WRAP) && /* wrapping wanted */
2027 (!Single_Line_Field(field)) && /* must be multi-line */
2028 (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line id full */
2029 (!Last_Row || Growable(field)) ) /* there are more lines*/
2033 int chars_to_be_wrapped;
2034 int chars_to_remain_on_line;
2036 { /* the above logic already ensures, that in this case the field
2038 if (!Field_Grown(field,1))
2039 return E_SYSTEM_ERROR;
2041 bp = Address_Of_Current_Row_In_Buffer(form);
2042 Window_To_Buffer(form->w,field);
2043 split = After_Last_Whitespace_Character(bp,field->dcols);
2044 /* split points to the first character of the sequence to be brought
2046 chars_to_remain_on_line = (int)(split - bp);
2047 chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2048 if (chars_to_remain_on_line > 0)
2050 if ((result=Insert_String(form,form->currow+1,split,
2051 chars_to_be_wrapped)) == E_OK)
2053 wmove(form->w,form->currow,chars_to_remain_on_line);
2055 if (form->curcol >= chars_to_remain_on_line)
2058 form->curcol -= chars_to_remain_on_line;
2065 wmove(form->w,form->currow,form->curcol);
2067 Window_To_Buffer(form->w,field);
2068 result = E_REQUEST_DENIED;
2072 result = E_OK; /* wrapping was not necessary */
2076 /*----------------------------------------------------------------------------
2077 Field Editing routines
2078 --------------------------------------------------------------------------*/
2080 /*---------------------------------------------------------------------------
2081 | Facility : libnform
2082 | Function : static int Field_Editing(
2083 | int (* const fct) (FORM *),
2086 | Description : Generic routine for field editing requests. The driver
2087 | routines are only called for editable fields, the
2088 | _WINDOW_MODIFIED flag is set if editing occured.
2089 | This is somewhat special due to the overload semantics
2090 | of the NEW_LINE and DEL_PREV requests.
2092 | Return Values : Error code from low level drivers.
2093 +--------------------------------------------------------------------------*/
2094 static int Field_Editing(int (* const fct) (FORM *), FORM * form)
2096 int res = E_REQUEST_DENIED;
2098 /* We have to deal here with the specific case of the overloaded
2099 behaviour of New_Line and Delete_Previous requests.
2100 They may end up in navigational requests if we are on the first
2101 character in a field. But navigation is also allowed on non-
2104 if ((fct==FE_Delete_Previous) &&
2105 (form->opts & O_BS_OVERLOAD) &&
2106 First_Position_In_Current_Field(form) )
2108 res = Inter_Field_Navigation(FN_Previous_Field,form);
2112 if (fct==FE_New_Line)
2114 if ((form->opts & O_NL_OVERLOAD) &&
2115 First_Position_In_Current_Field(form))
2117 res = Inter_Field_Navigation(FN_Next_Field,form);
2120 /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2125 /* From now on, everything must be editable */
2126 if (form->current->opts & O_EDIT)
2130 form->status |= _WINDOW_MODIFIED;
2137 /*---------------------------------------------------------------------------
2138 | Facility : libnform
2139 | Function : static int FE_New_Line(FORM * form)
2141 | Description : Perform a new line request. This is rather complex
2142 | compared to other routines in this code due to the
2143 | rather difficult to understand description in the
2146 | Return Values : E_OK - success
2147 | E_REQUEST_DENIED - new line not allowed
2148 | E_SYSTEM_ERROR - system error
2149 +--------------------------------------------------------------------------*/
2150 static int FE_New_Line(FORM * form)
2152 FIELD *field = form->current;
2154 bool Last_Row = ((field->drows - 1)==form->currow);
2156 if (form->status & _OVLMODE)
2159 (!(Growable(field) && !Single_Line_Field(field))))
2161 if (!(form->opts & O_NL_OVERLOAD))
2162 return(E_REQUEST_DENIED);
2164 /* we have to set this here, although it is also
2165 handled in the generic routine. The reason is,
2166 that FN_Next_Field may fail, but the form is
2167 definitively changed */
2168 form->status |= _WINDOW_MODIFIED;
2169 return Inter_Field_Navigation(FN_Next_Field,form);
2173 if (Last_Row && !Field_Grown(field,1))
2174 { /* N.B.: due to the logic in the 'if', LastRow==TRUE
2175 means here that the field is growable and not
2176 a single-line field */
2177 return(E_SYSTEM_ERROR);
2182 form->status |= _WINDOW_MODIFIED;
2189 !(Growable(field) && !Single_Line_Field(field)))
2191 if (!(form->opts & O_NL_OVERLOAD))
2192 return(E_REQUEST_DENIED);
2193 return Inter_Field_Navigation(FN_Next_Field,form);
2197 bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2199 if (!(May_Do_It || Growable(field)))
2200 return(E_REQUEST_DENIED);
2201 if (!May_Do_It && !Field_Grown(field,1))
2202 return(E_SYSTEM_ERROR);
2204 bp= Address_Of_Current_Position_In_Buffer(form);
2205 t = After_End_Of_Data(bp,field->dcols - form->curcol);
2209 wmove(form->w,form->currow,form->curcol);
2211 waddnstr(form->w,bp,(int)(t-bp));
2212 form->status |= _WINDOW_MODIFIED;
2218 /*---------------------------------------------------------------------------
2219 | Facility : libnform
2220 | Function : static int FE_Insert_Character(FORM * form)
2222 | Description : Insert blank character at the cursor position
2224 | Return Values : E_OK
2226 +--------------------------------------------------------------------------*/
2227 static int FE_Insert_Character(FORM * form)
2229 FIELD *field = form->current;
2230 int result = E_REQUEST_DENIED;
2232 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2234 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2236 if (There_Is_Room ||
2237 ((Single_Line_Field(field) && Growable(field))))
2239 if (!There_Is_Room && !Field_Grown(field,1))
2240 result = E_SYSTEM_ERROR;
2243 winsch(form->w,(chtype)C_BLANK);
2244 result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2251 /*---------------------------------------------------------------------------
2252 | Facility : libnform
2253 | Function : static int FE_Insert_Line(FORM * form)
2255 | Description : Insert a blank line at the cursor position
2257 | Return Values : E_OK - success
2258 | E_REQUEST_DENIED - line can not be inserted
2259 +--------------------------------------------------------------------------*/
2260 static int FE_Insert_Line(FORM * form)
2262 FIELD *field = form->current;
2263 int result = E_REQUEST_DENIED;
2265 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2267 bool Maybe_Done = (form->currow!=(field->drows-1)) &&
2268 Is_There_Room_For_A_Line(form);
2270 if (!Single_Line_Field(field) &&
2271 (Maybe_Done || Growable(field)))
2273 if (!Maybe_Done && !Field_Grown(field,1))
2274 result = E_SYSTEM_ERROR;
2286 /*---------------------------------------------------------------------------
2287 | Facility : libnform
2288 | Function : static int FE_Delete_Character(FORM * form)
2290 | Description : Delete character at the cursor position
2292 | Return Values : E_OK - success
2293 +--------------------------------------------------------------------------*/
2294 static int FE_Delete_Character(FORM * form)
2300 /*---------------------------------------------------------------------------
2301 | Facility : libnform
2302 | Function : static int FE_Delete_Previous(FORM * form)
2304 | Description : Delete character before cursor. Again this is a rather
2305 | difficult piece compared to others due to the overloading
2306 | semantics of backspace.
2307 | N.B.: The case of overloaded BS on first field position
2308 | is already handled in the generic routine.
2310 | Return Values : E_OK - success
2311 | E_REQUEST_DENIED - Character can't be deleted
2312 +--------------------------------------------------------------------------*/
2313 static int FE_Delete_Previous(FORM * form)
2315 FIELD *field = form->current;
2317 if (First_Position_In_Current_Field(form))
2318 return E_REQUEST_DENIED;
2320 if ( (--(form->curcol))<0 )
2322 char *this_line, *prev_line, *prev_end, *this_end;
2325 if (form->status & _OVLMODE)
2326 return E_REQUEST_DENIED;
2328 prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
2329 this_line = Address_Of_Row_In_Buffer(field,(form->currow));
2330 Synchronize_Buffer(form);
2331 prev_end = After_End_Of_Data(prev_line,field->dcols);
2332 this_end = After_End_Of_Data(this_line,field->dcols);
2333 if ((int)(this_end-this_line) >
2334 (field->cols-(int)(prev_end-prev_line)))
2335 return E_REQUEST_DENIED;
2337 Adjust_Cursor_Position(form,prev_end);
2338 wmove(form->w,form->currow,form->curcol);
2339 waddnstr(form->w,this_line,(int)(this_end-this_line));
2343 wmove(form->w,form->currow,form->curcol);
2349 /*---------------------------------------------------------------------------
2350 | Facility : libnform
2351 | Function : static int FE_Delete_Line(FORM * form)
2353 | Description : Delete line at cursor position.
2355 | Return Values : E_OK - success
2356 +--------------------------------------------------------------------------*/
2357 static int FE_Delete_Line(FORM * form)
2364 /*---------------------------------------------------------------------------
2365 | Facility : libnform
2366 | Function : static int FE_Delete_Word(FORM * form)
2368 | Description : Delete word at cursor position
2370 | Return Values : E_OK - success
2371 | E_REQUEST_DENIED - failure
2372 +--------------------------------------------------------------------------*/
2373 static int FE_Delete_Word(FORM * form)
2375 FIELD *field = form->current;
2376 char *bp = Address_Of_Current_Row_In_Buffer(form);
2377 char *ep = bp + field->dcols;
2378 char *cp = bp + form->curcol;
2381 Synchronize_Buffer(form);
2383 return E_REQUEST_DENIED; /* not in word */
2385 /* move cursor to begin of word and erase to end of screen-line */
2386 Adjust_Cursor_Position(form,
2387 After_Last_Whitespace_Character(bp,form->curcol));
2388 wmove(form->w,form->currow,form->curcol);
2391 /* skip over word in buffer */
2392 s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
2393 /* to begin of next word */
2394 s = Get_Start_Of_Data(s,(int)(ep - s));
2395 if ( (s!=cp) && !is_blank(*s))
2397 /* copy remaining line to window */
2398 waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
2403 /*---------------------------------------------------------------------------
2404 | Facility : libnform
2405 | Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2407 | Description : Clear to end of current line.
2409 | Return Values : E_OK - success
2410 +--------------------------------------------------------------------------*/
2411 static int FE_Clear_To_End_Of_Line(FORM * form)
2417 /*---------------------------------------------------------------------------
2418 | Facility : libnform
2419 | Function : static int FE_Clear_To_End_Of_Form(FORM * form)
2421 | Description : Clear to end of form.
2423 | Return Values : E_OK - success
2424 +--------------------------------------------------------------------------*/
2425 static int FE_Clear_To_End_Of_Form(FORM * form)
2431 /*---------------------------------------------------------------------------
2432 | Facility : libnform
2433 | Function : static int FE_Clear_Field(FORM * form)
2435 | Description : Clear entire field.
2437 | Return Values : E_OK - success
2438 +--------------------------------------------------------------------------*/
2439 static int FE_Clear_Field(FORM * form)
2441 form->currow = form->curcol = 0;
2445 /*----------------------------------------------------------------------------
2446 END of Field Editing routines
2447 --------------------------------------------------------------------------*/
2449 /*----------------------------------------------------------------------------
2451 --------------------------------------------------------------------------*/
2453 /*---------------------------------------------------------------------------
2454 | Facility : libnform
2455 | Function : static int EM_Overlay_Mode(FORM * form)
2457 | Description : Switch to overlay mode.
2459 | Return Values : E_OK - success
2460 +--------------------------------------------------------------------------*/
2461 static int EM_Overlay_Mode(FORM * form)
2463 form->status |= _OVLMODE;
2467 /*---------------------------------------------------------------------------
2468 | Facility : libnform
2469 | Function : static int EM_Insert_Mode(FORM * form)
2471 | Description : Switch to insert mode
2473 | Return Values : E_OK - success
2474 +--------------------------------------------------------------------------*/
2475 static int EM_Insert_Mode(FORM * form)
2477 form->status &= ~_OVLMODE;
2481 /*----------------------------------------------------------------------------
2482 END of Edit Mode routines
2483 --------------------------------------------------------------------------*/
2485 /*----------------------------------------------------------------------------
2486 Helper routines for Choice Requests
2487 --------------------------------------------------------------------------*/
2489 /*---------------------------------------------------------------------------
2490 | Facility : libnform
2491 | Function : static bool Next_Choice(
2494 | TypeArgument *argp)
2496 | Description : Get the next field choice. For linked types this is
2499 | Return Values : TRUE - next choice successfully retrieved
2500 | FALSE - couldn't retrieve next choice
2501 +--------------------------------------------------------------------------*/
2502 static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
2504 if (!typ || !(typ->status & _HAS_CHOICE))
2507 if (typ->status & _LINKED_TYPE)
2511 Next_Choice(typ->left ,field,argp->left) ||
2512 Next_Choice(typ->right,field,argp->right) );
2517 return typ->next(field,(void *)argp);
2521 /*---------------------------------------------------------------------------
2522 | Facility : libnform
2523 | Function : static bool Previous_Choice(
2526 | TypeArgument *argp)
2528 | Description : Get the previous field choice. For linked types this
2529 | is done recursively.
2531 | Return Values : TRUE - previous choice successfully retrieved
2532 | FALSE - couldn't retrieve previous choice
2533 +--------------------------------------------------------------------------*/
2534 static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2536 if (!typ || !(typ->status & _HAS_CHOICE))
2539 if (typ->status & _LINKED_TYPE)
2543 Previous_Choice(typ->left ,field,argp->left) ||
2544 Previous_Choice(typ->right,field,argp->right));
2549 return typ->prev(field,(void *)argp);
2552 /*----------------------------------------------------------------------------
2553 End of Helper routines for Choice Requests
2554 --------------------------------------------------------------------------*/
2556 /*----------------------------------------------------------------------------
2557 Routines for Choice Requests
2558 --------------------------------------------------------------------------*/
2560 /*---------------------------------------------------------------------------
2561 | Facility : libnform
2562 | Function : static int CR_Next_Choice(FORM * form)
2564 | Description : Get the next field choice.
2566 | Return Values : E_OK - success
2567 | E_REQUEST_DENIED - next choice couldn't be retrieved
2568 +--------------------------------------------------------------------------*/
2569 static int CR_Next_Choice(FORM * form)
2571 FIELD *field = form->current;
2572 Synchronize_Buffer(form);
2573 return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2574 E_OK : E_REQUEST_DENIED);
2577 /*---------------------------------------------------------------------------
2578 | Facility : libnform
2579 | Function : static int CR_Previous_Choice(FORM * form)
2581 | Description : Get the previous field choice.
2583 | Return Values : E_OK - success
2584 | E_REQUEST_DENIED - prev. choice couldn't be retrieved
2585 +--------------------------------------------------------------------------*/
2586 static int CR_Previous_Choice(FORM * form)
2588 FIELD *field = form->current;
2589 Synchronize_Buffer(form);
2590 return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2591 E_OK : E_REQUEST_DENIED);
2593 /*----------------------------------------------------------------------------
2594 End of Routines for Choice Requests
2595 --------------------------------------------------------------------------*/
2597 /*----------------------------------------------------------------------------
2598 Helper routines for Field Validations.
2599 --------------------------------------------------------------------------*/
2601 /*---------------------------------------------------------------------------
2602 | Facility : libnform
2603 | Function : static bool Check_Field(
2606 | TypeArgument * argp)
2608 | Description : Check the field according to its fieldtype and its
2609 | actual arguments. For linked fieldtypes this is done
2612 | Return Values : TRUE - field is valid
2613 | FALSE - field is invalid.
2614 +--------------------------------------------------------------------------*/
2615 static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2619 if (field->opts & O_NULLOK)
2621 char *bp = field->buf;
2623 while(is_blank(*bp))
2629 if (typ->status & _LINKED_TYPE)
2633 Check_Field(typ->left ,field,argp->left ) ||
2634 Check_Field(typ->right,field,argp->right) );
2639 return typ->fcheck(field,(void *)argp);
2645 /*---------------------------------------------------------------------------
2646 | Facility : libnform
2647 | Function : static bool Internal_Validation(FORM * form )
2649 | Description : Validate the current field of the form.
2651 | Return Values : TRUE - field is valid
2652 | FALSE - field is invalid
2653 +--------------------------------------------------------------------------*/
2654 static bool Internal_Validation(FORM *form)
2658 field = form->current;
2660 Synchronize_Buffer(form);
2661 if ((form->status & _FCHECK_REQUIRED) ||
2662 (!(field->opts & O_PASSOK)))
2664 if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
2666 form->status &= ~_FCHECK_REQUIRED;
2667 field->status |= _CHANGED;
2668 Synchronize_Linked_Fields(field);
2672 /*----------------------------------------------------------------------------
2673 End of Helper routines for Field Validations.
2674 --------------------------------------------------------------------------*/
2676 /*----------------------------------------------------------------------------
2677 Routines for Field Validation.
2678 --------------------------------------------------------------------------*/
2680 /*---------------------------------------------------------------------------
2681 | Facility : libnform
2682 | Function : static int FV_Validation(FORM * form)
2684 | Description : Validate the current field of the form.
2686 | Return Values : E_OK - field valid
2687 | E_INVALID_FIELD - field not valid
2688 +--------------------------------------------------------------------------*/
2689 static int FV_Validation(FORM * form)
2691 if (Internal_Validation(form))
2694 return E_INVALID_FIELD;
2696 /*----------------------------------------------------------------------------
2697 End of routines for Field Validation.
2698 --------------------------------------------------------------------------*/
2700 /*----------------------------------------------------------------------------
2701 Helper routines for Inter-Field Navigation
2702 --------------------------------------------------------------------------*/
2704 /*---------------------------------------------------------------------------
2705 | Facility : libnform
2706 | Function : static FIELD *Next_Field_On_Page(FIELD * field)
2708 | Description : Get the next field after the given field on the current
2709 | page. The order of fields is the one defined by the
2710 | fields array. Only visible and active fields are
2713 | Return Values : Pointer to the next field.
2714 +--------------------------------------------------------------------------*/
2715 INLINE static FIELD *Next_Field_On_Page(FIELD * field)
2717 FORM *form = field->form;
2718 FIELD **field_on_page = &form->field[field->index];
2719 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2720 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2725 (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
2726 if (Field_Is_Selectable(*field_on_page))
2728 } while(field!=(*field_on_page));
2729 return(*field_on_page);
2732 /*---------------------------------------------------------------------------
2733 | Facility : libnform
2734 | Function : static FIELD * First_Active_Field(FORM * form)
2736 | Description : Get the first active field on the current page,
2737 | if there are such. If there are none, get the first
2738 | visible field on the page. If there are also none,
2739 | we return the first field on page and hope the best.
2741 | Return Values : Pointer to calculated field.
2742 +--------------------------------------------------------------------------*/
2743 static FIELD * First_Active_Field(FORM * form)
2745 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2746 FIELD *proposed = Next_Field_On_Page(*last_on_page);
2748 if (proposed == *last_on_page)
2749 { /* there might be the special situation, where there is no
2750 active and visible field on the current page. We then select
2751 the first visible field on this readonly page
2753 if (Field_Is_Not_Selectable(proposed))
2755 FIELD **field = &form->field[proposed->index];
2756 FIELD **first = &form->field[form->page[form->curpage].pmin];
2760 field = (field==last_on_page) ? first : field + 1;
2761 if (((*field)->opts & O_VISIBLE))
2763 } while(proposed!=(*field));
2767 if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
2768 { /* This means, there is also no visible field on the page.
2769 So we propose the first one and hope the very best...
2770 Some very clever user has designed a readonly and invisible
2780 /*---------------------------------------------------------------------------
2781 | Facility : libnform
2782 | Function : static FIELD *Previous_Field_On_Page(FIELD * field)
2784 | Description : Get the previous field before the given field on the
2785 | current page. The order of fields is the one defined by
2786 | the fields array. Only visible and active fields are
2789 | Return Values : Pointer to the previous field.
2790 +--------------------------------------------------------------------------*/
2791 INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
2793 FORM *form = field->form;
2794 FIELD **field_on_page = &form->field[field->index];
2795 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2796 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2801 (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
2802 if (Field_Is_Selectable(*field_on_page))
2804 } while(field!=(*field_on_page));
2806 return (*field_on_page);
2809 /*---------------------------------------------------------------------------
2810 | Facility : libnform
2811 | Function : static FIELD *Sorted_Next_Field(FIELD * field)
2813 | Description : Get the next field after the given field on the current
2814 | page. The order of fields is the one defined by the
2815 | (row,column) geometry, rows are major.
2817 | Return Values : Pointer to the next field.
2818 +--------------------------------------------------------------------------*/
2819 INLINE static FIELD *Sorted_Next_Field(FIELD * field)
2821 FIELD *field_on_page = field;
2825 field_on_page = field_on_page->snext;
2826 if (Field_Is_Selectable(field_on_page))
2828 } while(field_on_page!=field);
2830 return (field_on_page);
2833 /*---------------------------------------------------------------------------
2834 | Facility : libnform
2835 | Function : static FIELD *Sorted_Previous_Field(FIELD * field)
2837 | Description : Get the previous field before the given field on the
2838 | current page. The order of fields is the one defined
2839 | by the (row,column) geometry, rows are major.
2841 | Return Values : Pointer to the previous field.
2842 +--------------------------------------------------------------------------*/
2843 INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
2845 FIELD *field_on_page = field;
2849 field_on_page = field_on_page->sprev;
2850 if (Field_Is_Selectable(field_on_page))
2852 } while(field_on_page!=field);
2854 return (field_on_page);
2857 /*---------------------------------------------------------------------------
2858 | Facility : libnform
2859 | Function : static FIELD *Left_Neighbour_Field(FIELD * field)
2861 | Description : Get the left neighbour of the field on the same line
2862 | and the same page. Cycles through the line.
2864 | Return Values : Pointer to left neighbour field.
2865 +--------------------------------------------------------------------------*/
2866 INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
2868 FIELD *field_on_page = field;
2870 /* For a field that has really a left neighbour, the while clause
2871 immediately fails and the loop is left, positioned at the right
2872 neighbour. Otherwise we cycle backwards through the sorted fieldlist
2873 until we enter the same line (from the right end).
2877 field_on_page = Sorted_Previous_Field(field_on_page);
2878 } while(field_on_page->frow != field->frow);
2880 return (field_on_page);
2883 /*---------------------------------------------------------------------------
2884 | Facility : libnform
2885 | Function : static FIELD *Right_Neighbour_Field(FIELD * field)
2887 | Description : Get the right neighbour of the field on the same line
2888 | and the same page.
2890 | Return Values : Pointer to right neighbour field.
2891 +--------------------------------------------------------------------------*/
2892 INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
2894 FIELD *field_on_page = field;
2896 /* See the comments on Left_Neighbour_Field to understand how it works */
2899 field_on_page = Sorted_Next_Field(field_on_page);
2900 } while(field_on_page->frow != field->frow);
2902 return (field_on_page);
2905 /*---------------------------------------------------------------------------
2906 | Facility : libnform
2907 | Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
2909 | Description : Because of the row-major nature of sorting the fields,
2910 | its more difficult to define whats the upper neighbour
2911 | field really means. We define that it must be on a
2912 | 'previous' line (cyclic order!) and is the rightmost
2913 | field laying on the left side of the given field. If
2914 | this set is empty, we take the first field on the line.
2916 | Return Values : Pointer to the upper neighbour field.
2917 +--------------------------------------------------------------------------*/
2918 static FIELD *Upper_Neighbour_Field(FIELD * field)
2920 FIELD *field_on_page = field;
2921 int frow = field->frow;
2922 int fcol = field->fcol;
2924 /* Walk back to the 'previous' line. The second term in the while clause
2925 just guarantees that we stop if we cycled through the line because
2926 there might be no 'previous' line if the page has just one line.
2930 field_on_page = Sorted_Previous_Field(field_on_page);
2931 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
2933 if (field_on_page->frow!=frow)
2934 { /* We really found a 'previous' line. We are positioned at the
2935 rightmost field on this line */
2936 frow = field_on_page->frow;
2938 /* We walk to the left as long as we are really right of the
2940 while(field_on_page->frow==frow && field_on_page->fcol>fcol)
2941 field_on_page = Sorted_Previous_Field(field_on_page);
2943 /* If we wrapped, just go to the right which is the first field on
2945 if (field_on_page->frow!=frow)
2946 field_on_page = Sorted_Next_Field(field_on_page);
2949 return (field_on_page);
2952 /*---------------------------------------------------------------------------
2953 | Facility : libnform
2954 | Function : static FIELD *Down_Neighbour_Field(FIELD * field)
2956 | Description : Because of the row-major nature of sorting the fields,
2957 | its more difficult to define whats the down neighbour
2958 | field really means. We define that it must be on a
2959 | 'next' line (cyclic order!) and is the leftmost
2960 | field laying on the right side of the given field. If
2961 | this set is empty, we take the last field on the line.
2963 | Return Values : Pointer to the upper neighbour field.
2964 +--------------------------------------------------------------------------*/
2965 static FIELD *Down_Neighbour_Field(FIELD * field)
2967 FIELD *field_on_page = field;
2968 int frow = field->frow;
2969 int fcol = field->fcol;
2971 /* Walk forward to the 'next' 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 'next' line if the page has just one line.
2977 field_on_page = Sorted_Next_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 'next' line. We are positioned at the rightmost
2982 field on this line */
2983 frow = field_on_page->frow;
2985 /* We walk to the right as long as we are really left of the
2987 while(field_on_page->frow==frow && field_on_page->fcol<fcol)
2988 field_on_page = Sorted_Next_Field(field_on_page);
2990 /* If we wrapped, just go to the left which is the last field on
2992 if (field_on_page->frow!=frow)
2993 field_on_page = Sorted_Previous_Field(field_on_page);
2996 return(field_on_page);
2999 /*----------------------------------------------------------------------------
3000 Inter-Field Navigation routines
3001 --------------------------------------------------------------------------*/
3003 /*---------------------------------------------------------------------------
3004 | Facility : libnform
3005 | Function : static int Inter_Field_Navigation(
3006 | int (* const fct) (FORM *),
3009 | Description : Generic behaviour for changing the current field, the
3010 | field is left and a new field is entered. So the field
3011 | must be validated and the field init/term hooks must
3014 | Return Values : E_OK - success
3015 | E_INVALID_FIELD - field is invalid
3016 | some other - error from subordinate call
3017 +--------------------------------------------------------------------------*/
3018 static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
3022 if (!Internal_Validation(form))
3023 res = E_INVALID_FIELD;
3026 Call_Hook(form,fieldterm);
3028 Call_Hook(form,fieldinit);
3033 /*---------------------------------------------------------------------------
3034 | Facility : libnform
3035 | Function : static int FN_Next_Field(FORM * form)
3037 | Description : Move to the next field on the current page of the form
3039 | Return Values : E_OK - success
3040 | != E_OK - error from subordinate call
3041 +--------------------------------------------------------------------------*/
3042 static int FN_Next_Field(FORM * form)
3044 return Set_Current_Field(form,
3045 Next_Field_On_Page(form->current));
3048 /*---------------------------------------------------------------------------
3049 | Facility : libnform
3050 | Function : static int FN_Previous_Field(FORM * form)
3052 | Description : Move to the previous field on the current page of the
3055 | Return Values : E_OK - success
3056 | != E_OK - error from subordinate call
3057 +--------------------------------------------------------------------------*/
3058 static int FN_Previous_Field(FORM * form)
3060 return Set_Current_Field(form,
3061 Previous_Field_On_Page(form->current));
3064 /*---------------------------------------------------------------------------
3065 | Facility : libnform
3066 | Function : static int FN_First_Field(FORM * form)
3068 | Description : Move to the first field on the current page of the form
3070 | Return Values : E_OK - success
3071 | != E_OK - error from subordinate call
3072 +--------------------------------------------------------------------------*/
3073 static int FN_First_Field(FORM * form)
3076 Set_Current_Field(form,
3077 Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
3080 /*---------------------------------------------------------------------------
3081 | Facility : libnform
3082 | Function : static int FN_Last_Field(FORM * form)
3084 | Description : Move to the last 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_Last_Field(FORM * form)
3092 Set_Current_Field(form,
3093 Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
3096 /*---------------------------------------------------------------------------
3097 | Facility : libnform
3098 | Function : static int FN_Sorted_Next_Field(FORM * form)
3100 | Description : Move to the sorted next field on the current page
3103 | Return Values : E_OK - success
3104 | != E_OK - error from subordinate call
3105 +--------------------------------------------------------------------------*/
3106 static int FN_Sorted_Next_Field(FORM * form)
3108 return Set_Current_Field(form,
3109 Sorted_Next_Field(form->current));
3112 /*---------------------------------------------------------------------------
3113 | Facility : libnform
3114 | Function : static int FN_Sorted_Previous_Field(FORM * form)
3116 | Description : Move to the sorted previous field on the current page
3119 | Return Values : E_OK - success
3120 | != E_OK - error from subordinate call
3121 +--------------------------------------------------------------------------*/
3122 static int FN_Sorted_Previous_Field(FORM * form)
3124 return Set_Current_Field(form,
3125 Sorted_Previous_Field(form->current));
3128 /*---------------------------------------------------------------------------
3129 | Facility : libnform
3130 | Function : static int FN_Sorted_First_Field(FORM * form)
3132 | Description : Move to the sorted first field on the current page
3135 | Return Values : E_OK - success
3136 | != E_OK - error from subordinate call
3137 +--------------------------------------------------------------------------*/
3138 static int FN_Sorted_First_Field(FORM * form)
3140 return Set_Current_Field(form,
3141 Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
3144 /*---------------------------------------------------------------------------
3145 | Facility : libnform
3146 | Function : static int FN_Sorted_Last_Field(FORM * form)
3148 | Description : Move to the sorted last field on the current page
3151 | Return Values : E_OK - success
3152 | != E_OK - error from subordinate call
3153 +--------------------------------------------------------------------------*/
3154 static int FN_Sorted_Last_Field(FORM * form)
3156 return Set_Current_Field(form,
3157 Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
3160 /*---------------------------------------------------------------------------
3161 | Facility : libnform
3162 | Function : static int FN_Left_Field(FORM * form)
3164 | Description : Get the field on the left of the current field on the
3165 | same line and the same page. Cycles through the line.
3167 | Return Values : E_OK - success
3168 | != E_OK - error from subordinate call
3169 +--------------------------------------------------------------------------*/
3170 static int FN_Left_Field(FORM * form)
3172 return Set_Current_Field(form,
3173 Left_Neighbour_Field(form->current));
3176 /*---------------------------------------------------------------------------
3177 | Facility : libnform
3178 | Function : static int FN_Right_Field(FORM * form)
3180 | Description : Get the field on the right of the current field on the
3181 | same line and the same page. Cycles through the line.
3183 | Return Values : E_OK - success
3184 | != E_OK - error from subordinate call
3185 +--------------------------------------------------------------------------*/
3186 static int FN_Right_Field(FORM * form)
3188 return Set_Current_Field(form,
3189 Right_Neighbour_Field(form->current));
3192 /*---------------------------------------------------------------------------
3193 | Facility : libnform
3194 | Function : static int FN_Up_Field(FORM * form)
3196 | Description : Get the upper neighbour of the current field. This
3197 | cycles through the page. See the comments of the
3198 | Upper_Neighbour_Field function to understand how
3199 | 'upper' is defined.
3201 | Return Values : E_OK - success
3202 | != E_OK - error from subordinate call
3203 +--------------------------------------------------------------------------*/
3204 static int FN_Up_Field(FORM * form)
3206 return Set_Current_Field(form,
3207 Upper_Neighbour_Field(form->current));
3210 /*---------------------------------------------------------------------------
3211 | Facility : libnform
3212 | Function : static int FN_Down_Field(FORM * form)
3214 | Description : Get the down neighbour of the current field. This
3215 | cycles through the page. See the comments of the
3216 | Down_Neighbour_Field function to understand how
3217 | 'down' is defined.
3219 | Return Values : E_OK - success
3220 | != E_OK - error from subordinate call
3221 +--------------------------------------------------------------------------*/
3222 static int FN_Down_Field(FORM * form)
3224 return Set_Current_Field(form,
3225 Down_Neighbour_Field(form->current));
3227 /*----------------------------------------------------------------------------
3228 END of Field Navigation routines
3229 --------------------------------------------------------------------------*/
3231 /*----------------------------------------------------------------------------
3232 Helper routines for Page Navigation
3233 --------------------------------------------------------------------------*/
3235 /*---------------------------------------------------------------------------
3236 | Facility : libnform
3237 | Function : static int Set_Form_Page(FORM * form,
3241 | Description : Make the given page nr. the current page and make
3242 | the given field the current field on the page. If
3243 | for the field NULL is given, make the first field on
3244 | the page the current field. The routine acts only
3245 | if the requested page is not the current page.
3247 | Return Values : E_OK - success
3248 | != E_OK - error from subordinate call
3249 +--------------------------------------------------------------------------*/
3250 static int Set_Form_Page(FORM * form, int page, FIELD * field)
3254 if ((form->curpage!=page))
3256 FIELD *last_field, *field_on_page;
3258 werase(Get_Form_Window(form));
3259 form->curpage = page;
3260 last_field = field_on_page = form->field[form->page[page].smin];
3263 if (field_on_page->opts & O_VISIBLE)
3264 if ((res=Display_Field(field_on_page))!=E_OK)
3266 field_on_page = field_on_page->snext;
3267 } while(field_on_page != last_field);
3270 res = Set_Current_Field(form,field);
3272 /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
3273 because this is already executed in a page navigation
3274 context that contains field navigation
3276 res = FN_First_Field(form);
3281 /*---------------------------------------------------------------------------
3282 | Facility : libnform
3283 | Function : static int Next_Page_Number(const FORM * form)
3285 | Description : Calculate the page number following the current page
3286 | number. This cycles if the highest page number is
3289 | Return Values : The next page number
3290 +--------------------------------------------------------------------------*/
3291 INLINE static int Next_Page_Number(const FORM * form)
3293 return (form->curpage + 1) % form->maxpage;
3296 /*---------------------------------------------------------------------------
3297 | Facility : libnform
3298 | Function : static int Previous_Page_Number(const FORM * form)
3300 | Description : Calculate the page number before the current page
3301 | number. This cycles if the first page number is
3304 | Return Values : The previous page number
3305 +--------------------------------------------------------------------------*/
3306 INLINE static int Previous_Page_Number(const FORM * form)
3308 return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
3311 /*----------------------------------------------------------------------------
3312 Page Navigation routines
3313 --------------------------------------------------------------------------*/
3315 /*---------------------------------------------------------------------------
3316 | Facility : libnform
3317 | Function : static int Page_Navigation(
3318 | int (* const fct) (FORM *),
3321 | Description : Generic behaviour for changing a page. This means
3322 | that the field is left and a new field is entered.
3323 | So the field must be validated and the field init/term
3324 | hooks must be called. Because also the page is changed,
3325 | the forms init/term hooks must be called also.
3327 | Return Values : E_OK - success
3328 | E_INVALID_FIELD - field is invalid
3329 | some other - error from subordinate call
3330 +--------------------------------------------------------------------------*/
3331 static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
3335 if (!Internal_Validation(form))
3336 res = E_INVALID_FIELD;
3339 Call_Hook(form,fieldterm);
3340 Call_Hook(form,formterm);
3342 Call_Hook(form,forminit);
3343 Call_Hook(form,fieldinit);
3348 /*---------------------------------------------------------------------------
3349 | Facility : libnform
3350 | Function : static int PN_Next_Page(FORM * form)
3352 | Description : Move to the next page of the form
3354 | Return Values : E_OK - success
3355 | != E_OK - error from subordinate call
3356 +--------------------------------------------------------------------------*/
3357 static int PN_Next_Page(FORM * form)
3359 return Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
3362 /*---------------------------------------------------------------------------
3363 | Facility : libnform
3364 | Function : static int PN_Previous_Page(FORM * form)
3366 | Description : Move to the previous page of the form
3368 | Return Values : E_OK - success
3369 | != E_OK - error from subordinate call
3370 +--------------------------------------------------------------------------*/
3371 static int PN_Previous_Page(FORM * form)
3373 return Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
3376 /*---------------------------------------------------------------------------
3377 | Facility : libnform
3378 | Function : static int PN_First_Page(FORM * form)
3380 | Description : Move to the first page of the form
3382 | Return Values : E_OK - success
3383 | != E_OK - error from subordinate call
3384 +--------------------------------------------------------------------------*/
3385 static int PN_First_Page(FORM * form)
3387 return Set_Form_Page(form,0,(FIELD *)0);
3390 /*---------------------------------------------------------------------------
3391 | Facility : libnform
3392 | Function : static int PN_Last_Page(FORM * form)
3394 | Description : Move to the last page of the form
3396 | Return Values : E_OK - success
3397 | != E_OK - error from subordinate call
3398 +--------------------------------------------------------------------------*/
3399 static int PN_Last_Page(FORM * form)
3401 return Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
3403 /*----------------------------------------------------------------------------
3404 END of Field Navigation routines
3405 --------------------------------------------------------------------------*/
3407 /*----------------------------------------------------------------------------
3408 Helper routines for the core form driver.
3409 --------------------------------------------------------------------------*/
3411 /*---------------------------------------------------------------------------
3412 | Facility : libnform
3413 | Function : static int Data_Entry(FORM * form,int c)
3415 | Description : Enter character c into at the current position of the
3416 | current field of the form.
3418 | Return Values : E_OK -
3419 | E_REQUEST_DENIED -
3421 +--------------------------------------------------------------------------*/
3422 static int Data_Entry(FORM * form, int c)
3424 FIELD *field = form->current;
3425 int result = E_REQUEST_DENIED;
3428 if ( (field->opts & O_EDIT)
3429 #if FIX_FORM_INACTIVE_BUG
3430 && (field->opts & O_ACTIVE)
3434 if ( (field->opts & O_BLANK) &&
3435 First_Position_In_Current_Field(form) &&
3436 !(form->status & _FCHECK_REQUIRED) &&
3437 !(form->status & _WINDOW_MODIFIED) )
3440 if (form->status & _OVLMODE)
3442 waddch(form->w,(chtype)c);
3444 else /* no _OVLMODE */
3446 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
3448 if (!(There_Is_Room ||
3449 ((Single_Line_Field(field) && Growable(field)))))
3450 return E_REQUEST_DENIED;
3452 if (!There_Is_Room && !Field_Grown(field,1))
3453 return E_SYSTEM_ERROR;
3455 winsch(form->w,(chtype)c);
3458 if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
3460 form->status |= _WINDOW_MODIFIED;
3461 End_Of_Field= (((field->drows-1)==form->currow) &&
3462 ((field->dcols-1)==form->curcol));
3463 if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3464 result = Inter_Field_Navigation(FN_Next_Field,form);
3467 if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
3468 result = E_SYSTEM_ERROR;
3471 IFN_Next_Character(form);
3480 /* Structure to describe the binding of a request code to a function.
3481 The member keycode codes the request value as well as the generic
3482 routine to use for the request. The code for the generic routine
3483 is coded in the upper 16 Bits while the request code is coded in
3486 In terms of C++ you might think of a request as a class with a
3487 virtual method "perform". The different types of request are
3488 derived from this base class and overload (or not) the base class
3489 implementation of perform.
3492 int keycode; /* must be at least 32 bit: hi:mode, lo: key */
3493 int (*cmd)(FORM *); /* low level driver routine for this key */
3496 /* You may see this is the class-id of the request type class */
3497 #define ID_PN (0x00000000) /* Page navigation */
3498 #define ID_FN (0x00010000) /* Inter-Field navigation */
3499 #define ID_IFN (0x00020000) /* Intra-Field navigation */
3500 #define ID_VSC (0x00030000) /* Vertical Scrolling */
3501 #define ID_HSC (0x00040000) /* Horizontal Scrolling */
3502 #define ID_FE (0x00050000) /* Field Editing */
3503 #define ID_EM (0x00060000) /* Edit Mode */
3504 #define ID_FV (0x00070000) /* Field Validation */
3505 #define ID_CH (0x00080000) /* Choice */
3506 #define ID_Mask (0xffff0000)
3507 #define Key_Mask (0x0000ffff)
3508 #define ID_Shft (16)
3510 /* This array holds all the Binding Infos */
3511 static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
3513 { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
3514 { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
3515 { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
3516 { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
3518 { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
3519 { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
3520 { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
3521 { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
3522 { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
3523 { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
3524 { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
3525 { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
3526 { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
3527 { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
3528 { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
3529 { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
3531 { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
3532 { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
3533 { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
3534 { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
3535 { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
3536 { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
3537 { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
3538 { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
3539 { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
3540 { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
3541 { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
3542 { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
3543 { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
3544 { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
3546 { REQ_NEW_LINE |ID_FE ,FE_New_Line},
3547 { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
3548 { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
3549 { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
3550 { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
3551 { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
3552 { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
3553 { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
3554 { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
3555 { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
3557 { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
3558 { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
3560 { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
3561 { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
3562 { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
3563 { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
3564 { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
3565 { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
3567 { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
3568 { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
3569 { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
3570 { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
3571 { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
3572 { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
3574 { REQ_VALIDATION |ID_FV ,FV_Validation},
3576 { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
3577 { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
3580 /*---------------------------------------------------------------------------
3581 | Facility : libnform
3582 | Function : int form_driver(FORM * form,int c)
3584 | Description : This is the workhorse of the forms system. It checks
3585 | to determine whether the character c is a request or
3586 | data. If it is a request, the form driver executes
3587 | the request and returns the result. If it is data
3588 | (printable character), it enters the data into the
3589 | current position in the current field. If it is not
3590 | recognized, the form driver assumes it is an application
3591 | defined command and returns E_UNKNOWN_COMMAND.
3592 | Application defined command should be defined relative
3593 | to MAX_FORM_COMMAND, the maximum value of a request.
3595 | Return Values : E_OK - success
3596 | E_SYSTEM_ERROR - system error
3597 | E_BAD_ARGUMENT - an argument is incorrect
3598 | E_NOT_POSTED - form is not posted
3599 | E_INVALID_FIELD - field contents are invalid
3600 | E_BAD_STATE - called from inside a hook routine
3601 | E_REQUEST_DENIED - request failed
3602 | E_UNKNOWN_COMMAND - command not known
3603 +--------------------------------------------------------------------------*/
3604 int form_driver(FORM * form, int c)
3606 const Binding_Info* BI = (Binding_Info *)0;
3607 int res = E_UNKNOWN_COMMAND;
3610 RETURN(E_BAD_ARGUMENT);
3613 RETURN(E_NOT_CONNECTED);
3617 if (c==FIRST_ACTIVE_MAGIC)
3619 form->current = First_Active_Field(form);
3623 assert(form->current &&
3624 form->current->buf &&
3625 (form->current->form == form)
3628 if ( form->status & _IN_DRIVER )
3629 RETURN(E_BAD_STATE);
3631 if ( !( form->status & _POSTED ) )
3632 RETURN(E_NOT_POSTED);
3634 if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
3635 ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
3636 BI = &(bindings[c-MIN_FORM_COMMAND]);
3640 typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
3641 static const Generic_Method Generic_Methods[] =
3643 Page_Navigation, /* overloaded to call field&form hooks */
3644 Inter_Field_Navigation, /* overloaded to call field hooks */
3645 NULL, /* Intra-Field is generic */
3646 Vertical_Scrolling, /* Overloaded to check multi-line */
3647 Horizontal_Scrolling, /* Overloaded to check single-line */
3648 Field_Editing, /* Overloaded to mark modification */
3649 NULL, /* Edit Mode is generic */
3650 NULL, /* Field Validation is generic */
3651 NULL /* Choice Request is generic */
3653 int nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
3654 int method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
3656 if ( (method < 0) || (method >= nMethods) || !(BI->cmd) )
3657 res = E_SYSTEM_ERROR;
3660 Generic_Method fct = Generic_Methods[method];
3662 res = fct(BI->cmd,form);
3664 res = (BI->cmd)(form);
3669 if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
3670 isprint((unsigned char)c) &&
3671 Check_Char(form->current->type,c,
3672 (TypeArgument *)(form->current->arg)))
3673 res = Data_Entry(form,c);
3675 Refresh_Current_Field(form);
3679 /*---------------------------------------------------------------------------
3680 | Facility : libnform
3681 | Function : int post_form(FORM * form)
3683 | Description : Writes the form into its associated subwindow.
3685 | Return Values : E_OK - success
3686 | E_BAD_ARGUMENT - invalid form pointer
3687 | E_POSTED - form already posted
3688 | E_NOT_CONNECTED - no fields connected to form
3689 | E_NO_ROOM - form doesn't fit into subwindow
3690 | E_SYSTEM_ERROR - system error
3691 +--------------------------------------------------------------------------*/
3692 int post_form(FORM * form)
3699 RETURN(E_BAD_ARGUMENT);
3701 if (form->status & _POSTED)
3705 RETURN(E_NOT_CONNECTED);
3707 formwin = Get_Form_Window(form);
3708 if ((form->cols > getmaxx(formwin)) || (form->rows > getmaxy(formwin)))
3711 /* reset form->curpage to an invald value. This forces Set_Form_Page
3712 to do the page initialization which is required by post_form.
3714 page = form->curpage;
3716 if ((err = Set_Form_Page(form,page,form->current))!=E_OK)
3719 form->status |= _POSTED;
3721 Call_Hook(form,forminit);
3722 Call_Hook(form,fieldinit);
3724 Refresh_Current_Field(form);
3728 /*---------------------------------------------------------------------------
3729 | Facility : libnform
3730 | Function : int unpost_form(FORM * form)
3732 | Description : Erase form from its associated subwindow.
3734 | Return Values : E_OK - success
3735 | E_BAD_ARGUMENT - invalid form pointer
3736 | E_NOT_POSTED - form isn't posted
3737 | E_BAD_STATE - called from a hook routine
3738 +--------------------------------------------------------------------------*/
3739 int unpost_form(FORM * form)
3742 RETURN(E_BAD_ARGUMENT);
3744 if (!(form->status & _POSTED))
3745 RETURN(E_NOT_POSTED);
3747 if (form->status & _IN_DRIVER)
3748 RETURN(E_BAD_STATE);
3750 Call_Hook(form,fieldterm);
3751 Call_Hook(form,formterm);
3753 werase(Get_Form_Window(form));
3755 form->w = (WINDOW *)0;
3756 form->status &= ~_POSTED;
3760 /*---------------------------------------------------------------------------
3761 | Facility : libnform
3762 | Function : int pos_form_cursor(FORM * form)
3764 | Description : Moves the form window cursor to the location required
3765 | by the form driver to resume form processing. This may
3766 | be needed after the application calls a curses library
3767 | I/O routine that modifies the cursor position.
3769 | Return Values : E_OK - Success
3770 | E_SYSTEM_ERROR - System error.
3771 | E_BAD_ARGUMENT - Invalid form pointer
3772 | E_NOT_POSTED - Form is not posted
3773 +--------------------------------------------------------------------------*/
3774 int pos_form_cursor(FORM * form)
3779 res = E_BAD_ARGUMENT;
3782 if (!(form->status & _POSTED))
3785 res = Position_Form_Cursor(form);
3790 /*---------------------------------------------------------------------------
3791 | Facility : libnform
3792 | Function : int set_current_field(FORM * form,FIELD * field)
3794 | Description : Set the current field of the form to the specified one.
3796 | Return Values : E_OK - success
3797 | E_BAD_ARGUMENT - invalid form or field pointer
3798 | E_REQUEST_DENIED - field not selectable
3799 | E_BAD_STATE - called from a hook routine
3800 | E_INVALID_FIELD - current field can't be left
3801 | E_SYSTEM_ERROR - system error
3802 +--------------------------------------------------------------------------*/
3803 int set_current_field(FORM * form, FIELD * field)
3807 if ( !form || !field )
3808 RETURN(E_BAD_ARGUMENT);
3810 if ( (form != field->form) || Field_Is_Not_Selectable(field) )
3811 RETURN(E_REQUEST_DENIED);
3813 if (!(form->status & _POSTED))
3815 form->current = field;
3816 form->curpage = field->page;
3820 if (form->status & _IN_DRIVER)
3824 if (form->current != field)
3826 if (!Internal_Validation(form))
3827 err = E_INVALID_FIELD;
3830 Call_Hook(form,fieldterm);
3831 if (field->page != form->curpage)
3833 Call_Hook(form,formterm);
3834 err = Set_Form_Page(form,field->page,field);
3835 Call_Hook(form,forminit);
3839 err = Set_Current_Field(form,field);
3841 Call_Hook(form,fieldinit);
3842 Refresh_Current_Field(form);
3850 /*---------------------------------------------------------------------------
3851 | Facility : libnform
3852 | Function : FIELD *current_field(const FORM * form)
3854 | Description : Return the current field.
3856 | Return Values : Pointer to the current field.
3857 +--------------------------------------------------------------------------*/
3858 FIELD *current_field(const FORM * form)
3860 return Normalize_Form(form)->current;
3863 /*---------------------------------------------------------------------------
3864 | Facility : libnform
3865 | Function : int field_index(const FIELD * field)
3867 | Description : Return the index of the field in the field-array of
3870 | Return Values : >= 0 : field index
3871 | -1 : fieldpointer invalid or field not connected
3872 +--------------------------------------------------------------------------*/
3873 int field_index(const FIELD * field)
3875 return ( (field && field->form) ? field->index : -1 );
3878 /*---------------------------------------------------------------------------
3879 | Facility : libnform
3880 | Function : int set_form_page(FORM * form,int page)
3882 | Description : Set the page number of the form.
3884 | Return Values : E_OK - success
3885 | E_BAD_ARGUMENT - invalid form pointer or page number
3886 | E_BAD_STATE - called from a hook routine
3887 | E_INVALID_FIELD - current field can't be left
3888 | E_SYSTEM_ERROR - system error
3889 +--------------------------------------------------------------------------*/
3890 int set_form_page(FORM * form, int page)
3894 if ( !form || (page<0) || (page>=form->maxpage) )
3895 RETURN(E_BAD_ARGUMENT);
3897 if (!(form->status & _POSTED))
3899 form->curpage = page;
3900 form->current = First_Active_Field(form);
3904 if (form->status & _IN_DRIVER)
3908 if (form->curpage != page)
3910 if (!Internal_Validation(form))
3911 err = E_INVALID_FIELD;
3914 Call_Hook(form,fieldterm);
3915 Call_Hook(form,formterm);
3916 err = Set_Form_Page(form,page,(FIELD *)0);
3917 Call_Hook(form,forminit);
3918 Call_Hook(form,fieldinit);
3919 Refresh_Current_Field(form);
3927 /*---------------------------------------------------------------------------
3928 | Facility : libnform
3929 | Function : int form_page(const FORM * form)
3931 | Description : Return the current page of the form.
3933 | Return Values : >= 0 : current page number
3934 | -1 : invalid form pointer
3935 +--------------------------------------------------------------------------*/
3936 int form_page(const FORM * form)
3938 return Normalize_Form(form)->curpage;
3941 /*----------------------------------------------------------------------------
3942 Field-Buffer manipulation routines
3943 --------------------------------------------------------------------------*/
3945 /*---------------------------------------------------------------------------
3946 | Facility : libnform
3947 | Function : int set_field_buffer(FIELD *field,
3948 | int buffer, char *value)
3950 | Description : Set the given buffer of the field to the given value.
3951 | Buffer 0 stores the displayed content of the field.
3952 | For dynamic fields this may grow the fieldbuffers if
3953 | the length of the value exceeds the current buffer
3954 | length. For buffer 0 only printable values are allowed.
3955 | For static fields, the value needs not to be zero ter-
3956 | minated. It is copied up to the length of the buffer.
3958 | Return Values : E_OK - success
3959 | E_BAD_ARGUMENT - invalid argument
3960 | E_SYSTEM_ERROR - system error
3961 +--------------------------------------------------------------------------*/
3962 int set_field_buffer(FIELD * field, int buffer, const char * value)
3968 if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
3969 RETURN(E_BAD_ARGUMENT);
3971 len = Buffer_Length(field);
3978 for(v=value; *v && (i<len); v++,i++)
3980 if (!isprint((unsigned char)*v))
3981 RETURN(E_BAD_ARGUMENT);
3985 if (Growable(field))
3987 /* for a growable field we must assume zero terminated strings, because
3988 somehow we have to detect the length of what should be copied.
3990 unsigned int vlen = strlen(value);
3993 if (!Field_Grown(field,
3994 (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
3995 RETURN(E_SYSTEM_ERROR);
3997 /* in this case we also have to check, wether or not the remaining
3998 characters in value are also printable for buffer 0. */
4003 for(i=len; i<vlen; i++)
4004 if (!isprint(value[i]))
4005 RETURN(E_BAD_ARGUMENT);
4011 p = Address_Of_Nth_Buffer(field,buffer);
4014 s = memccpy(p,value,0,len);
4016 for(s=(char *)value; *s && (s < (value+len)); s++)
4018 if (s < (value+len))
4025 { /* this means, value was null terminated and not greater than the
4026 buffer. We have to pad with blanks */
4027 assert(len >= (unsigned int)(s-p));
4028 if (len > (unsigned int)(s-p))
4029 memset(s,C_BLANK,len-(unsigned int)(s-p));
4035 if (((syncres=Synchronize_Field( field ))!=E_OK) &&
4038 if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
4045 /*---------------------------------------------------------------------------
4046 | Facility : libnform
4047 | Function : char *field_buffer(const FIELD *field,int buffer)
4049 | Description : Return the address of the buffer for the field.
4051 | Return Values : Pointer to buffer or NULL if arguments were invalid.
4052 +--------------------------------------------------------------------------*/
4053 char *field_buffer(const FIELD * field, int buffer)
4055 if (field && (buffer >= 0) && (buffer <= field->nbuf))
4056 return Address_Of_Nth_Buffer(field,buffer);
4061 /*----------------------------------------------------------------------------
4062 Field-Options manipulation routines
4063 --------------------------------------------------------------------------*/
4065 /*---------------------------------------------------------------------------
4066 | Facility : libnform
4067 | Function : int set_field_opts(FIELD *field, Field_Options opts)
4069 | Description : Turns on the named options for this field and turns
4070 | off all the remaining options.
4072 | Return Values : E_OK - success
4073 | E_CURRENT - the field is the current field
4074 | E_BAD_ARGUMENT - invalid options
4075 | E_SYSTEM_ERROR - system error
4076 +--------------------------------------------------------------------------*/
4077 int set_field_opts(FIELD * field, Field_Options opts)
4079 int res = E_BAD_ARGUMENT;
4080 if (!(opts & ~ALL_FIELD_OPTS))
4081 res = Synchronize_Options( Normalize_Field(field), opts );
4085 /*---------------------------------------------------------------------------
4086 | Facility : libnform
4087 | Function : Field_Options field_opts(const FIELD *field)
4089 | Description : Retrieve the fields options.
4091 | Return Values : The options.
4092 +--------------------------------------------------------------------------*/
4093 Field_Options field_opts(const FIELD * field)
4095 return ALL_FIELD_OPTS & Normalize_Field( field )->opts;
4098 /*---------------------------------------------------------------------------
4099 | Facility : libnform
4100 | Function : int field_opts_on(FIELD *field, Field_Options opts)
4102 | Description : Turns on the named options for this field and all the
4103 | remaining options are unchanged.
4105 | Return Values : E_OK - success
4106 | E_CURRENT - the field is the current field
4107 | E_BAD_ARGUMENT - invalid options
4108 | E_SYSTEM_ERROR - system error
4109 +--------------------------------------------------------------------------*/
4110 int field_opts_on(FIELD * field, Field_Options opts)
4112 int res = E_BAD_ARGUMENT;
4114 if (!(opts & ~ALL_FIELD_OPTS))
4116 Normalize_Field( field );
4117 res = Synchronize_Options( field, field->opts | opts );
4122 /*---------------------------------------------------------------------------
4123 | Facility : libnform
4124 | Function : int field_opts_off(FIELD *field, Field_Options opts)
4126 | Description : Turns off the named options for this field and all the
4127 | remaining options are unchanged.
4129 | Return Values : E_OK - success
4130 | E_CURRENT - the field is the current field
4131 | E_BAD_ARGUMENT - invalid options
4132 | E_SYSTEM_ERROR - system error
4133 +--------------------------------------------------------------------------*/
4134 int field_opts_off(FIELD * field, Field_Options opts)
4136 int res = E_BAD_ARGUMENT;
4138 if (!(opts & ~ALL_FIELD_OPTS))
4140 Normalize_Field( field );
4141 res = Synchronize_Options( field, field->opts & ~opts );
4146 /*----------------------------------------------------------------------------
4147 Field-Attribute manipulation routines
4148 --------------------------------------------------------------------------*/
4149 /* "Template" macro to generate a function to set a fields attribute */
4150 #define GEN_FIELD_ATTR_SET_FCT( name ) \
4151 int set_field_ ## name (FIELD * field, chtype attr)\
4153 int res = E_BAD_ARGUMENT;\
4154 if ( attr==A_NORMAL || ((attr & A_ATTRIBUTES)==attr) )\
4156 Normalize_Field( field );\
4157 if ((field -> name) != attr)\
4159 field -> name = attr;\
4160 res = Synchronize_Attributes( field );\
4168 /* "Template" macro to generate a function to get a fields attribute */
4169 #define GEN_FIELD_ATTR_GET_FCT( name ) \
4170 chtype field_ ## name (const FIELD * field)\
4172 return ( A_ATTRIBUTES & (Normalize_Field( field ) -> name) );\
4175 /*---------------------------------------------------------------------------
4176 | Facility : libnform
4177 | Function : int set_field_fore(FIELD *field, chtype attr)
4179 | Description : Sets the foreground of the field used to display the
4182 | Return Values : E_OK - success
4183 | E_BAD_ARGUMENT - invalid attributes
4184 | E_SYSTEM_ERROR - system error
4185 +--------------------------------------------------------------------------*/
4186 GEN_FIELD_ATTR_SET_FCT( fore )
4188 /*---------------------------------------------------------------------------
4189 | Facility : libnform
4190 | Function : chtype field_fore(const FIELD *)
4192 | Description : Retrieve fields foreground attribute
4194 | Return Values : The foreground attribute
4195 +--------------------------------------------------------------------------*/
4196 GEN_FIELD_ATTR_GET_FCT( fore )
4198 /*---------------------------------------------------------------------------
4199 | Facility : libnform
4200 | Function : int set_field_back(FIELD *field, chtype attr)
4202 | Description : Sets the background of the field used to display the
4205 | Return Values : E_OK - success
4206 | E_BAD_ARGUMENT - invalid attributes
4207 | E_SYSTEM_ERROR - system error
4208 +--------------------------------------------------------------------------*/
4209 GEN_FIELD_ATTR_SET_FCT( back )
4211 /*---------------------------------------------------------------------------
4212 | Facility : libnform
4213 | Function : chtype field_back(const
4215 | Description : Retrieve fields background attribute
4217 | Return Values : The background attribute
4218 +--------------------------------------------------------------------------*/
4219 GEN_FIELD_ATTR_GET_FCT( back )
4221 /*---------------------------------------------------------------------------
4222 | Facility : libnform
4223 | Function : int set_field_pad(FIELD *field, int ch)
4225 | Description : Set the pad character used to fill the field. This must
4226 | be a printable character.
4228 | Return Values : E_OK - success
4229 | E_BAD_ARGUMENT - invalid field pointer or pad character
4230 | E_SYSTEM_ERROR - system error
4231 +--------------------------------------------------------------------------*/
4232 int set_field_pad(FIELD * field, int ch)
4234 int res = E_BAD_ARGUMENT;
4236 Normalize_Field( field );
4237 if (isprint((unsigned char)ch))
4239 if (field->pad != ch)
4242 res = Synchronize_Attributes( field );
4250 /*---------------------------------------------------------------------------
4251 | Facility : libnform
4252 | Function : int field_pad(const FIELD *field)
4254 | Description : Retrieve the fields pad character.
4256 | Return Values : The pad character.
4257 +--------------------------------------------------------------------------*/
4258 int field_pad(const FIELD * field)
4260 return Normalize_Field( field )->pad;
4263 /*---------------------------------------------------------------------------
4264 | Facility : libnform
4265 | Function : int set_field_just(FIELD *field, int just)
4267 | Description : Set the fields type of justification.
4269 | Return Values : E_OK - success
4270 | E_BAD_ARGUMENT - one of the arguments was incorrect
4271 | E_SYSTEM_ERROR - system error
4272 +--------------------------------------------------------------------------*/
4273 int set_field_just(FIELD * field, int just)
4275 int res = E_BAD_ARGUMENT;
4277 if ((just==NO_JUSTIFICATION) ||
4278 (just==JUSTIFY_LEFT) ||
4279 (just==JUSTIFY_CENTER) ||
4280 (just==JUSTIFY_RIGHT) )
4282 Normalize_Field( field );
4283 if (field->just != just)
4286 res = Synchronize_Attributes( field );
4294 /*---------------------------------------------------------------------------
4295 | Facility : libnform
4296 | Function : int field_just( const FIELD *field )
4298 | Description : Retrieve the fields type of justification
4300 | Return Values : The justification type.
4301 +--------------------------------------------------------------------------*/
4302 int field_just(const FIELD * field)
4304 return Normalize_Field( field )->just;
4307 /* frm_driver.c ends here */