Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / CursesDialog / form / frm_driver.c
bloba2deec1c1cb21cf34c4f655e3c3d1aded14c4583
1 /****************************************************************************
2 * Copyright (c) 1998 Free Software Foundation, Inc. *
3 * *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
11 * *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
14 * *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 * *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
26 * authorization. *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 *
31 ****************************************************************************/
32 #if defined(__hpux)
33 #define _XOPEN_SOURCE_EXTENDED
34 #endif
35 #include "form.priv.h"
36 #if defined(__hpux)
37 #undef _XOPEN_SOURCE_EXTENDED
38 #endif
40 /* AIX seems to define this */
41 #undef lines
42 #undef columns
44 MODULE_ID("$Id: frm_driver.c,v 1.15 2002/10/23 20:43:34 king Exp $")
46 /* These declarations are missing from curses.h on some platforms. */
47 extern int winnstr(WINDOW *, char *, int);
48 #if defined(__DECCXX_VER) || (defined(__GNUC__) && defined(__osf__))
49 extern int waddnstr(WINDOW *,const char *const,int);
50 extern void wbkgdset(WINDOW *,chtype);
51 #ifndef untouchwin
52 extern int untouchwin(WINDOW *);
53 #endif
54 extern void wcursyncup(WINDOW *);
55 extern int copywin(const WINDOW*,WINDOW*,int,int,int,int,int,int,int);
56 extern bool is_linetouched(WINDOW *,int);
57 extern void wsyncup(WINDOW *);
58 extern WINDOW *derwin(WINDOW *,int,int,int,int);
59 extern int winsnstr(WINDOW *, const char *,int);
60 extern int winsdelln(WINDOW *,int);
61 #endif
63 /*----------------------------------------------------------------------------
64 This is the core module of the form library. It contains the majority
65 of the driver routines as well as the form_driver function.
67 Essentially this module is nearly the whole library. This is because
68 all the functions in this module depends on some others in the module,
69 so it makes no sense to split them into separate files because they
70 will always be linked together. The only acceptable concern is turnaround
71 time for this module, but now we have all Pentiums or Riscs, so what!
73 The driver routines are grouped into nine generic categories:
75 a) Page Navigation ( all functions prefixed by PN_ )
76 The current page of the form is left and some new page is
77 entered.
78 b) Inter-Field Navigation ( all functions prefixed by FN_ )
79 The current field of the form is left and some new field is
80 entered.
81 c) Intra-Field Navigation ( all functions prefixed by IFN_ )
82 The current position in the current field is changed.
83 d) Vertical Scrolling ( all functions prefixed by VSC_ )
84 Esseantially this is a specialization of Intra-Field navigation.
85 It has to check for a multi-line field.
86 e) Horizontal Scrolling ( all functions prefixed by HSC_ )
87 Esseantially this is a specialization of Intra-Field navigation.
88 It has to check for a single-line field.
89 f) Field Editing ( all functions prefixed by FE_ )
90 The content of the current field is changed
91 g) Edit Mode requests ( all functions prefixed by EM_ )
92 Switching between insert and overlay mode
93 h) Field-Validation requests ( all functions prefixed by FV_ )
94 Perform verifications of the field.
95 i) Choice requests ( all functions prefixed by CR_ )
96 Requests to enumerate possible field values
97 --------------------------------------------------------------------------*/
99 /*----------------------------------------------------------------------------
100 Some remarks on the placements of assert() macros :
101 I use them only on "strategic" places, i.e. top level entries where
102 I want to make sure that things are set correctly. Throughout subordinate
103 routines I omit them mostly.
104 --------------------------------------------------------------------------*/
107 Some options that may effect compatibility in behavior to SVr4 forms,
108 but they are here to allow a more intuitive and user friendly behaviour of
109 our form implementation. This doesn't affect the API, so we feel it is
110 uncritical.
112 The initial implementation tries to stay very close with the behaviour
113 of the original SVr4 implementation, although in some areas it is quite
114 clear that this isn't the most appropriate way. As far as possible this
115 sources will allow you to build a forms lib that behaves quite similar
116 to SVr4, but now and in the future we will give you better options.
117 Perhaps at some time we will make this configurable at runtime.
120 /* Implement a more user-friendly previous/next word behaviour */
121 #define FRIENDLY_PREV_NEXT_WORD (1)
122 /* Fix the wrong behaviour for forms with all fields inactive */
123 #define FIX_FORM_INACTIVE_BUG (1)
124 /* Allow dynamic field growth also when navigating past the end */
125 #define GROW_IF_NAVIGATE (1)
127 /*----------------------------------------------------------------------------
128 Forward references to some internally used static functions
129 --------------------------------------------------------------------------*/
130 static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
131 static int FN_Next_Field (FORM * form);
132 static int FN_Previous_Field (FORM * form);
133 static int FE_New_Line(FORM *);
134 static int FE_Delete_Previous(FORM *);
136 /*----------------------------------------------------------------------------
137 Macro Definitions.
139 Some Remarks on that: I use the convention to use UPPERCASE for constants
140 defined by Macros. If I provide a macro as a kind of inline routine to
141 provide some logic, I use my Upper_Lower case style.
142 --------------------------------------------------------------------------*/
144 /* Calculate the position of a single row in a field buffer */
145 #define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
147 /* Calculate start address for the fields buffer# N */
148 #define Address_Of_Nth_Buffer(field,N) \
149 ((field)->buf + (N)*(1+Buffer_Length(field)))
151 /* Calculate the start address of the row in the fields specified buffer# N */
152 #define Address_Of_Row_In_Nth_Buffer(field,N,row) \
153 (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
155 /* Calculate the start address of the row in the fields primary buffer */
156 #define Address_Of_Row_In_Buffer(field,row) \
157 Address_Of_Row_In_Nth_Buffer(field,0,row)
159 /* Calculate the start address of the row in the forms current field
160 buffer# N */
161 #define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
162 Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
164 /* Calculate the start address of the row in the forms current field
165 primary buffer */
166 #define Address_Of_Current_Row_In_Buffer(form) \
167 Address_Of_Current_Row_In_Nth_Buffer(form,0)
169 /* Calculate the address of the cursor in the forms current field
170 primary buffer */
171 #define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
172 (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
174 /* Calculate the address of the cursor in the forms current field
175 buffer# N */
176 #define Address_Of_Current_Position_In_Buffer(form) \
177 Address_Of_Current_Position_In_Nth_Buffer(form,0)
179 /* Logic to decide wether or not a field is actually a field with
180 vertical or horizontal scrolling */
181 #define Is_Scroll_Field(field) \
182 (((field)->drows > (field)->rows) || \
183 ((field)->dcols > (field)->cols))
185 /* Logic to decide whether or not a field needs to have an individual window
186 instead of a derived window because it contains invisible parts.
187 This is true for non-public fields and for scrollable fields. */
188 #define Has_Invisible_Parts(field) \
189 (!((field)->opts & O_PUBLIC) || \
190 Is_Scroll_Field(field))
192 /* Logic to decide whether or not a field needs justification */
193 #define Justification_Allowed(field) \
194 (((field)->just != NO_JUSTIFICATION) && \
195 (Single_Line_Field(field)) && \
196 (((field)->dcols == (field)->cols) && \
197 ((field)->opts & O_STATIC)) )
199 /* Logic to determine whether or not a dynamic field may still grow */
200 #define Growable(field) ((field)->status & _MAY_GROW)
202 /* Macro to set the attributes for a fields window */
203 #define Set_Field_Window_Attributes(field,win) \
204 ( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
205 wattrset((win),(field)->fore) )
207 /* Logic to decide whether or not a field really appears on the form */
208 #define Field_Really_Appears(field) \
209 ((field->form) &&\
210 (field->form->status & _POSTED) &&\
211 (field->opts & O_VISIBLE) &&\
212 (field->page == field->form->curpage))
214 /* Logic to determine whether or not we are on the first position in the
215 current field */
216 #define First_Position_In_Current_Field(form) \
217 (((form)->currow==0) && ((form)->curcol==0))
220 #define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
221 #define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
223 /*---------------------------------------------------------------------------
224 | Facility : libnform
225 | Function : static char *Get_Start_Of_Data(char * buf, int blen)
227 | Description : Return pointer to first non-blank position in buffer.
228 | If buffer is empty return pointer to buffer itself.
230 | Return Values : Pointer to first non-blank position in buffer
231 +--------------------------------------------------------------------------*/
232 INLINE static char *Get_Start_Of_Data(char * buf, int blen)
234 char *p = buf;
235 char *end = &buf[blen];
237 assert(buf && blen>=0);
238 while( (p < end) && is_blank(*p) )
239 p++;
240 return( (p==end) ? buf : p );
243 /*---------------------------------------------------------------------------
244 | Facility : libnform
245 | Function : static char *After_End_Of_Data(char * buf, int blen)
247 | Description : Return pointer after last non-blank position in buffer.
248 | If buffer is empty, return pointer to buffer itself.
250 | Return Values : Pointer to position after last non-blank position in
251 | buffer.
252 +--------------------------------------------------------------------------*/
253 INLINE static char *After_End_Of_Data(char * buf,int blen)
255 char *p = &buf[blen];
257 assert(buf && blen>=0);
258 while( (p>buf) && is_blank(p[-1]) )
259 p--;
260 return( p );
263 /*---------------------------------------------------------------------------
264 | Facility : libnform
265 | Function : static char *Get_First_Whitespace_Character(
266 | char * buf, int blen)
268 | Description : Position to the first whitespace character.
270 | Return Values : Pointer to first whitespace character in buffer.
271 +--------------------------------------------------------------------------*/
272 INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
274 char *p = buf;
275 char *end = &p[blen];
277 assert(buf && blen>=0);
278 while( (p < end) && !is_blank(*p))
279 p++;
280 return( (p==end) ? buf : p );
283 /*---------------------------------------------------------------------------
284 | Facility : libnform
285 | Function : static char *After_Last_Whitespace_Character(
286 | char * buf, int blen)
288 | Description : Get the position after the last whitespace character.
290 | Return Values : Pointer to position after last whitespace character in
291 | buffer.
292 +--------------------------------------------------------------------------*/
293 INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
295 char *p = &buf[blen];
297 assert(buf && blen>=0);
298 while( (p>buf) && !is_blank(p[-1]) )
299 p--;
300 return( p );
303 /* Set this to 1 to use the div_t version. This is a good idea if your
304 compiler has an intrinsic div() support. Unfortunately GNU-C has it
305 not yet.
306 N.B.: This only works if form->curcol follows immediately form->currow
307 and both are of type int.
309 #define USE_DIV_T (0)
311 /*---------------------------------------------------------------------------
312 | Facility : libnform
313 | Function : static void Adjust_Cursor_Position(
314 | FORM * form, const char * pos)
316 | Description : Set current row and column of the form to values
317 | corresponding to the buffer position.
319 | Return Values : -
320 +--------------------------------------------------------------------------*/
321 INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
323 FIELD *field;
324 int idx;
326 field = form->current;
327 assert( pos >= field->buf && field->dcols > 0);
328 idx = (int)( pos - field->buf );
329 #if USE_DIV_T
330 *((div_t *)&(form->currow)) = div(idx,field->dcols);
331 #else
332 form->currow = idx / field->dcols;
333 form->curcol = idx - field->cols * form->currow;
334 #endif
335 if ( field->drows < form->currow )
336 form->currow = 0;
339 /*---------------------------------------------------------------------------
340 | Facility : libnform
341 | Function : static void Buffer_To_Window(
342 | const FIELD * field,
343 | WINDOW * win)
345 | Description : Copy the buffer to the window. If its a multiline
346 | field, the buffer is split to the lines of the
347 | window without any editing.
349 | Return Values : -
350 +--------------------------------------------------------------------------*/
351 static void Buffer_To_Window(const FIELD * field, WINDOW * win)
353 int width, height;
354 int len;
355 int row;
356 char *pBuffer;
358 assert(win && field);
360 width = getmaxx(win);
361 height = getmaxy(win);
363 for(row=0, pBuffer=field->buf;
364 row < height;
365 row++, pBuffer += width )
367 if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
369 wmove( win, row, 0 );
370 waddnstr( win, pBuffer, len );
375 /*---------------------------------------------------------------------------
376 | Facility : libnform
377 | Function : static void Window_To_Buffer(
378 | WINDOW * win,
379 | FIELD * field)
381 | Description : Copy the content of the window into the buffer.
382 | The multiple lines of a window are simply
383 | concatenated into the buffer. Pad characters in
384 | the window will be replaced by blanks in the buffer.
386 | Return Values : -
387 +--------------------------------------------------------------------------*/
388 static void Window_To_Buffer(WINDOW * win, FIELD * field)
390 int pad;
391 int len = 0;
392 char *p;
393 int row, height;
395 assert(win && field && field->buf );
397 pad = field->pad;
398 p = field->buf;
399 height = getmaxy(win);
401 for(row=0; (row < height) && (row < field->drows); row++ )
403 wmove( win, row, 0 );
404 len += winnstr( win, p+len, field->dcols );
406 p[len] = '\0';
408 /* replace visual padding character by blanks in buffer */
409 if (pad != C_BLANK)
411 int i;
412 for(i=0; i<len; i++, p++)
414 if (*p==pad)
415 *p = C_BLANK;
420 /*---------------------------------------------------------------------------
421 | Facility : libnform
422 | Function : static void Synchronize_Buffer(FORM * form)
424 | Description : If there was a change, copy the content of the
425 | window into the buffer, so the buffer is synchronized
426 | with the windows content. We have to indicate that the
427 | buffer needs validation due to the change.
429 | Return Values : -
430 +--------------------------------------------------------------------------*/
431 INLINE static void Synchronize_Buffer(FORM * form)
433 if (form->status & _WINDOW_MODIFIED)
435 form->status &= ~_WINDOW_MODIFIED;
436 form->status |= _FCHECK_REQUIRED;
437 Window_To_Buffer(form->w,form->current);
438 wmove(form->w,form->currow,form->curcol);
442 /*---------------------------------------------------------------------------
443 | Facility : libnform
444 | Function : static bool Field_Grown( FIELD *field, int amount)
446 | Description : This function is called for growable dynamic fields
447 | only. It has to increase the buffers and to allocate
448 | a new window for this field.
449 | This function has the side effect to set a new
450 | field-buffer pointer, the dcols and drows values
451 | as well as a new current Window for the field.
453 | Return Values : TRUE - field successfully increased
454 | FALSE - there was some error
455 +--------------------------------------------------------------------------*/
456 static bool Field_Grown(FIELD * field, int amount)
458 bool result = FALSE;
460 if (field && Growable(field))
462 bool single_line_field = Single_Line_Field(field);
463 int old_buflen = Buffer_Length(field);
464 int new_buflen;
465 int old_dcols = field->dcols;
466 int old_drows = field->drows;
467 char *oldbuf = field->buf;
468 char *newbuf;
470 int growth;
471 FORM *form = field->form;
472 bool need_visual_update = ((form != (FORM *)0) &&
473 (form->status & _POSTED) &&
474 (form->current==field));
476 if (need_visual_update)
477 Synchronize_Buffer(form);
479 if (single_line_field)
481 growth = field->cols * amount;
482 if (field->maxgrow)
483 growth = Minimum(field->maxgrow - field->dcols,growth);
484 field->dcols += growth;
485 if (field->dcols == field->maxgrow)
486 field->status &= ~_MAY_GROW;
488 else
490 growth = (field->rows + field->nrow) * amount;
491 if (field->maxgrow)
492 growth = Minimum(field->maxgrow - field->drows,growth);
493 field->drows += growth;
494 if (field->drows == field->maxgrow)
495 field->status &= ~_MAY_GROW;
497 /* drows, dcols changed, so we get really the new buffer length */
498 new_buflen = Buffer_Length(field);
499 newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
500 if (!newbuf)
501 { /* restore to previous state */
502 field->dcols = old_dcols;
503 field->drows = old_drows;
504 if (( single_line_field && (field->dcols!=field->maxgrow)) ||
505 (!single_line_field && (field->drows!=field->maxgrow)))
506 field->status |= _MAY_GROW;
507 return FALSE;
509 else
510 { /* Copy all the buffers. This is the reason why we can't
511 just use realloc().
513 int i;
514 char *old_bp;
515 char *new_bp;
517 field->buf = newbuf;
518 for(i=0;i<=field->nbuf;i++)
520 new_bp = Address_Of_Nth_Buffer(field,i);
521 old_bp = oldbuf + i*(1+old_buflen);
522 memcpy(new_bp,old_bp,(size_t)old_buflen);
523 if (new_buflen > old_buflen)
524 memset(new_bp + old_buflen,C_BLANK,
525 (size_t)(new_buflen - old_buflen));
526 *(new_bp + new_buflen) = '\0';
529 if (need_visual_update)
531 WINDOW *new_window = newpad(field->drows,field->dcols);
532 if (!new_window)
533 { /* restore old state */
534 field->dcols = old_dcols;
535 field->drows = old_drows;
536 field->buf = oldbuf;
537 if (( single_line_field &&
538 (field->dcols!=field->maxgrow)) ||
539 (!single_line_field &&
540 (field->drows!=field->maxgrow)))
541 field->status |= _MAY_GROW;
542 free( newbuf );
543 return FALSE;
545 assert(form!=(FORM *)0);
546 delwin(form->w);
547 form->w = new_window;
548 Set_Field_Window_Attributes(field,form->w);
549 werase(form->w);
550 Buffer_To_Window(field,form->w);
551 untouchwin(form->w);
552 wmove(form->w,form->currow,form->curcol);
555 free(oldbuf);
556 /* reflect changes in linked fields */
557 if (field != field->link)
559 FIELD *linked_field;
560 for(linked_field = field->link;
561 linked_field!= field;
562 linked_field = linked_field->link)
564 linked_field->buf = field->buf;
565 linked_field->drows = field->drows;
566 linked_field->dcols = field->dcols;
569 result = TRUE;
572 return(result);
575 /*---------------------------------------------------------------------------
576 | Facility : libnform
577 | Function : int _nc_Position_Form_Cursor(FORM * form)
579 | Description : Position the cursor in the window for the current
580 | field to be in sync. with the currow and curcol
581 | values.
583 | Return Values : E_OK - success
584 | E_BAD_ARGUMENT - invalid form pointer
585 | E_SYSTEM_ERROR - form has no current field or
586 | field-window
587 +--------------------------------------------------------------------------*/
589 _nc_Position_Form_Cursor(FORM * form)
591 FIELD *field;
592 WINDOW *formwin;
594 if (!form)
595 return(E_BAD_ARGUMENT);
597 if (!form->w || !form->current)
598 return(E_SYSTEM_ERROR);
600 field = form->current;
601 formwin = Get_Form_Window(form);
603 wmove( form->w, form->currow, form->curcol );
604 if ( Has_Invisible_Parts(field) )
606 /* in this case fieldwin isn't derived from formwin, so we have
607 to move the cursor in formwin by hand... */
608 wmove(formwin,
609 field->frow + form->currow - form->toprow,
610 field->fcol + form->curcol - form->begincol);
611 wcursyncup(formwin);
613 else
614 wcursyncup(form->w);
615 return(E_OK);
618 /*---------------------------------------------------------------------------
619 | Facility : libnform
620 | Function : int _nc_Refresh_Current_Field(FORM * form)
622 | Description : Propagate the changes in the fields window to the
623 | window of the form.
625 | Return Values : E_OK - on success
626 | E_BAD_ARGUMENT - invalid form pointer
627 | E_SYSTEM_ERROR - general error
628 +--------------------------------------------------------------------------*/
630 _nc_Refresh_Current_Field(FORM * form)
632 WINDOW *formwin;
633 FIELD *field;
635 if (!form)
636 RETURN(E_BAD_ARGUMENT);
638 if (!form->w || !form->current)
639 RETURN(E_SYSTEM_ERROR);
641 field = form->current;
642 formwin = Get_Form_Window(form);
644 if (field->opts & O_PUBLIC)
646 if (Is_Scroll_Field(field))
648 /* Again, in this case the fieldwin isn't derived from formwin,
649 so we have to perform a copy operation. */
650 if (Single_Line_Field(field))
651 { /* horizontal scrolling */
652 if (form->curcol < form->begincol)
653 form->begincol = form->curcol;
654 else
656 if (form->curcol >= (form->begincol + field->cols))
657 form->begincol = form->curcol - field->cols + 1;
659 copywin(form->w,
660 formwin,
662 form->begincol,
663 field->frow,
664 field->fcol,
665 field->frow,
666 field->cols + field->fcol - 1,
669 else
670 { /* A multiline, i.e. vertical scrolling field */
671 int row_after_bottom,first_modified_row,first_unmodified_row;
673 if (field->drows > field->rows)
675 row_after_bottom = form->toprow + field->rows;
676 if (form->currow < form->toprow)
678 form->toprow = form->currow;
679 field->status |= _NEWTOP;
681 if (form->currow >= row_after_bottom)
683 form->toprow = form->currow - field->rows + 1;
684 field->status |= _NEWTOP;
686 if (field->status & _NEWTOP)
687 { /* means we have to copy whole range */
688 first_modified_row = form->toprow;
689 first_unmodified_row = first_modified_row + field->rows;
690 field->status &= ~_NEWTOP;
692 else
693 { /* we try to optimize : finding the range of touched
694 lines */
695 first_modified_row = form->toprow;
696 while(first_modified_row < row_after_bottom)
698 if (is_linetouched(form->w,first_modified_row))
699 break;
700 first_modified_row++;
702 first_unmodified_row = first_modified_row;
703 while(first_unmodified_row < row_after_bottom)
705 if (!is_linetouched(form->w,first_unmodified_row))
706 break;
707 first_unmodified_row++;
711 else
713 first_modified_row = form->toprow;
714 first_unmodified_row = first_modified_row + field->rows;
716 if (first_unmodified_row != first_modified_row)
717 copywin(form->w,
718 formwin,
719 first_modified_row,
721 field->frow + first_modified_row - form->toprow,
722 field->fcol,
723 field->frow + first_unmodified_row - form->toprow - 1,
724 field->cols + field->fcol - 1,
727 wsyncup(formwin);
729 else
730 { /* if the field-window is simply a derived window, i.e. contains
731 no invisible parts, the whole thing is trivial
733 wsyncup(form->w);
736 untouchwin(form->w);
737 return _nc_Position_Form_Cursor(form);
740 /*---------------------------------------------------------------------------
741 | Facility : libnform
742 | Function : static void Perform_Justification(
743 | FIELD * field,
744 | WINDOW * win)
746 | Description : Output field with requested justification
748 | Return Values : -
749 +--------------------------------------------------------------------------*/
750 static void Perform_Justification(FIELD * field, WINDOW * win)
752 char *bp;
753 int len;
754 int col = 0;
756 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
757 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
759 if (len>0)
761 assert(win && (field->drows == 1) && (field->dcols == field->cols));
763 switch(field->just)
765 case JUSTIFY_LEFT:
766 break;
767 case JUSTIFY_CENTER:
768 col = (field->cols - len)/2;
769 break;
770 case JUSTIFY_RIGHT:
771 col = field->cols - len;
772 break;
773 default:
774 break;
777 wmove(win,0,col);
778 waddnstr(win,bp,len);
782 /*---------------------------------------------------------------------------
783 | Facility : libnform
784 | Function : static void Undo_Justification(
785 | FIELD * field,
786 | WINDOW * win)
788 | Description : Display field without any justification, i.e.
789 | left justified
791 | Return Values : -
792 +--------------------------------------------------------------------------*/
793 static void Undo_Justification(FIELD * field, WINDOW * win)
795 char *bp;
796 int len;
798 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
799 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
801 if (len>0)
803 assert(win != 0);
804 wmove(win,0,0);
805 waddnstr(win,bp,len);
809 /*---------------------------------------------------------------------------
810 | Facility : libnform
811 | Function : static bool Check_Char(
812 | FIELDTYPE * typ,
813 | int ch,
814 | TypeArgument *argp)
816 | Description : Perform a single character check for character ch
817 | according to the fieldtype instance.
819 | Return Values : TRUE - Character is valid
820 | FALSE - Character is invalid
821 +--------------------------------------------------------------------------*/
822 static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
824 if (typ)
826 if (typ->status & _LINKED_TYPE)
828 assert(argp != 0);
829 return(
830 Check_Char(typ->left ,ch,argp->left ) ||
831 Check_Char(typ->right,ch,argp->right) );
833 else
835 if (typ->ccheck)
836 return typ->ccheck(ch,(void *)argp);
839 return (isprint((unsigned char)ch) ? TRUE : FALSE);
842 /*---------------------------------------------------------------------------
843 | Facility : libnform
844 | Function : static int Display_Or_Erase_Field(
845 | FIELD * field,
846 | bool bEraseFlag)
848 | Description : Create a subwindow for the field and display the
849 | buffer contents (apply justification if required)
850 | or simply erase the field.
852 | Return Values : E_OK - on success
853 | E_SYSTEM_ERROR - some error (typical no memory)
854 +--------------------------------------------------------------------------*/
855 static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
857 WINDOW *win;
858 WINDOW *fwin;
860 if (!field)
861 return E_SYSTEM_ERROR;
863 fwin = Get_Form_Window(field->form);
864 win = derwin(fwin,
865 field->rows,field->cols,field->frow,field->fcol);
867 if (!win)
868 return E_SYSTEM_ERROR;
869 else
871 if (field->opts & O_VISIBLE)
872 Set_Field_Window_Attributes(field,win);
873 else
874 wattrset(win,getattrs(fwin));
875 werase(win);
878 if (!bEraseFlag)
880 if (field->opts & O_PUBLIC)
882 if (Justification_Allowed(field))
883 Perform_Justification(field,win);
884 else
885 Buffer_To_Window(field,win);
887 field->status &= ~_NEWTOP;
889 wsyncup(win);
890 delwin(win);
891 return E_OK;
894 /* Macros to preset the bEraseFlag */
895 #define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
896 #define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
898 /*---------------------------------------------------------------------------
899 | Facility : libnform
900 | Function : static int Synchronize_Field(FIELD * field)
902 | Description : Synchronize the windows content with the value in
903 | the buffer.
905 | Return Values : E_OK - success
906 | E_BAD_ARGUMENT - invalid field pointer
907 | E_SYSTEM_ERROR - some severe basic error
908 +--------------------------------------------------------------------------*/
909 static int Synchronize_Field(FIELD * field)
911 FORM *form;
912 int res = E_OK;
914 if (!field)
915 return(E_BAD_ARGUMENT);
917 if (((form=field->form) != (FORM *)0)
918 && Field_Really_Appears(field))
920 if (field == form->current)
922 form->currow = form->curcol = form->toprow = form->begincol = 0;
923 werase(form->w);
925 if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
926 Undo_Justification( field, form->w );
927 else
928 Buffer_To_Window( field, form->w );
930 field->status |= _NEWTOP;
931 res = _nc_Refresh_Current_Field( form );
933 else
934 res = Display_Field( field );
936 field->status |= _CHANGED;
937 return(res);
940 /*---------------------------------------------------------------------------
941 | Facility : libnform
942 | Function : static int Synchronize_Linked_Fields(FIELD * field)
944 | Description : Propagate the Synchronize_Field function to all linked
945 | fields. The first error that occurs in the sequence
946 | of updates is the returnvalue.
948 | Return Values : E_OK - success
949 | E_BAD_ARGUMENT - invalid field pointer
950 | E_SYSTEM_ERROR - some severe basic error
951 +--------------------------------------------------------------------------*/
952 static int Synchronize_Linked_Fields(FIELD * field)
954 FIELD *linked_field;
955 int res = E_OK;
956 int syncres;
958 if (!field)
959 return(E_BAD_ARGUMENT);
961 if (!field->link)
962 return(E_SYSTEM_ERROR);
964 for(linked_field = field->link;
965 linked_field!= field;
966 linked_field = linked_field->link )
968 if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
969 (res==E_OK))
970 res = syncres;
972 return(res);
975 /*---------------------------------------------------------------------------
976 | Facility : libnform
977 | Function : int _nc_Synchronize_Attributes(FIELD * field)
979 | Description : If a fields visual attributes have changed, this
980 | routine is called to propagate those changes to the
981 | screen.
983 | Return Values : E_OK - success
984 | E_BAD_ARGUMENT - invalid field pointer
985 | E_SYSTEM_ERROR - some severe basic error
986 +--------------------------------------------------------------------------*/
987 int _nc_Synchronize_Attributes(FIELD * field)
989 FORM *form;
990 int res = E_OK;
991 WINDOW *formwin;
993 if (!field)
994 return(E_BAD_ARGUMENT);
996 if (((form=field->form) != (FORM *)0)
997 && Field_Really_Appears(field))
999 if (form->current==field)
1001 Synchronize_Buffer(form);
1002 Set_Field_Window_Attributes(field,form->w);
1003 werase(form->w);
1004 if (field->opts & O_PUBLIC)
1006 if (Justification_Allowed(field))
1007 Undo_Justification(field,form->w);
1008 else
1009 Buffer_To_Window(field,form->w);
1011 else
1013 formwin = Get_Form_Window(form);
1014 copywin(form->w,formwin,
1015 0,0,
1016 field->frow,field->fcol,
1017 field->rows-1,field->cols-1,0);
1018 wsyncup(formwin);
1019 Buffer_To_Window(field,form->w);
1020 field->status |= _NEWTOP; /* fake refresh to paint all */
1021 _nc_Refresh_Current_Field(form);
1024 else
1026 res = Display_Field(field);
1029 return(res);
1032 /*---------------------------------------------------------------------------
1033 | Facility : libnform
1034 | Function : int _nc_Synchronize_Options(FIELD * field,
1035 | Field_Options newopts)
1037 | Description : If a fields options have changed, this routine is
1038 | called to propagate these changes to the screen and
1039 | to really change the behaviour of the field.
1041 | Return Values : E_OK - success
1042 | E_BAD_ARGUMENT - invalid field pointer
1043 | E_SYSTEM_ERROR - some severe basic error
1044 +--------------------------------------------------------------------------*/
1046 _nc_Synchronize_Options(FIELD *field, Field_Options newopts)
1048 Field_Options oldopts;
1049 Field_Options changed_opts;
1050 FORM *form;
1051 int res = E_OK;
1053 if (!field)
1054 return(E_BAD_ARGUMENT);
1056 oldopts = field->opts;
1057 changed_opts = oldopts ^ newopts;
1058 field->opts = newopts;
1059 form = field->form;
1061 if (form)
1063 if (form->current == field)
1065 field->opts = oldopts;
1066 return(E_CURRENT);
1069 if (form->status & _POSTED)
1071 if ((form->curpage == field->page))
1073 if (changed_opts & O_VISIBLE)
1075 if (newopts & O_VISIBLE)
1076 res = Display_Field(field);
1077 else
1078 res = Erase_Field(field);
1080 else
1082 if ((changed_opts & O_PUBLIC) &&
1083 (newopts & O_VISIBLE))
1084 res = Display_Field(field);
1090 if (changed_opts & O_STATIC)
1092 bool single_line_field = Single_Line_Field(field);
1093 int res2 = E_OK;
1095 if (newopts & O_STATIC)
1096 { /* the field becomes now static */
1097 field->status &= ~_MAY_GROW;
1098 /* if actually we have no hidden columns, justification may
1099 occur again */
1100 if (single_line_field &&
1101 (field->cols == field->dcols) &&
1102 (field->just != NO_JUSTIFICATION) &&
1103 Field_Really_Appears(field))
1105 res2 = Display_Field(field);
1108 else
1109 { /* field is no longer static */
1110 if ((field->maxgrow==0) ||
1111 ( single_line_field && (field->dcols < field->maxgrow)) ||
1112 (!single_line_field && (field->drows < field->maxgrow)))
1114 field->status |= _MAY_GROW;
1115 /* a field with justification now changes its behaviour,
1116 so we must redisplay it */
1117 if (single_line_field &&
1118 (field->just != NO_JUSTIFICATION) &&
1119 Field_Really_Appears(field))
1121 res2 = Display_Field(field);
1125 if (res2 != E_OK)
1126 res = res2;
1129 return(res);
1132 /*---------------------------------------------------------------------------
1133 | Facility : libnform
1134 | Function : int _nc_Set_Current_Field(FORM * form,
1135 | FIELD * newfield)
1137 | Description : Make the newfield the new current field.
1139 | Return Values : E_OK - success
1140 | E_BAD_ARGUMENT - invalid form or field pointer
1141 | E_SYSTEM_ERROR - some severe basic error
1142 +--------------------------------------------------------------------------*/
1144 _nc_Set_Current_Field(FORM *form, FIELD *newfield)
1146 FIELD *field;
1147 WINDOW *new_window;
1149 if (!form || !newfield || !form->current || (newfield->form!=form))
1150 return(E_BAD_ARGUMENT);
1152 if ( (form->status & _IN_DRIVER) )
1153 return(E_BAD_STATE);
1155 if (!(form->field))
1156 return(E_NOT_CONNECTED);
1158 field = form->current;
1160 if ((field!=newfield) ||
1161 !(form->status & _POSTED))
1163 if ((form->w) &&
1164 (field->opts & O_VISIBLE) &&
1165 (field->form->curpage == field->page))
1167 _nc_Refresh_Current_Field(form);
1168 if (field->opts & O_PUBLIC)
1170 if (field->drows > field->rows)
1172 if (form->toprow==0)
1173 field->status &= ~_NEWTOP;
1174 else
1175 field->status |= _NEWTOP;
1177 else
1179 if (Justification_Allowed(field))
1181 Window_To_Buffer(form->w,field);
1182 werase(form->w);
1183 Perform_Justification(field,form->w);
1184 wsyncup(form->w);
1188 delwin(form->w);
1191 field = newfield;
1193 if (Has_Invisible_Parts(field))
1194 new_window = newpad(field->drows,field->dcols);
1195 else
1196 new_window = derwin(Get_Form_Window(form),
1197 field->rows,field->cols,field->frow,field->fcol);
1199 if (!new_window)
1200 return(E_SYSTEM_ERROR);
1202 form->current = field;
1203 form->w = new_window;
1204 form->status &= ~_WINDOW_MODIFIED;
1205 Set_Field_Window_Attributes(field,form->w);
1207 if (Has_Invisible_Parts(field))
1209 werase(form->w);
1210 Buffer_To_Window(field,form->w);
1212 else
1214 if (Justification_Allowed(field))
1216 werase(form->w);
1217 Undo_Justification(field,form->w);
1218 wsyncup(form->w);
1222 untouchwin(form->w);
1225 form->currow = form->curcol = form->toprow = form->begincol = 0;
1226 return(E_OK);
1229 /*----------------------------------------------------------------------------
1230 Intra-Field Navigation routines
1231 --------------------------------------------------------------------------*/
1233 /*---------------------------------------------------------------------------
1234 | Facility : libnform
1235 | Function : static int IFN_Next_Character(FORM * form)
1237 | Description : Move to the next character in the field. In a multiline
1238 | field this wraps at the end of the line.
1240 | Return Values : E_OK - success
1241 | E_REQUEST_DENIED - at the rightmost position
1242 +--------------------------------------------------------------------------*/
1243 static int IFN_Next_Character(FORM * form)
1245 FIELD *field = form->current;
1247 if ((++(form->curcol))==field->dcols)
1249 if ((++(form->currow))==field->drows)
1251 #if GROW_IF_NAVIGATE
1252 if (!Single_Line_Field(field) && Field_Grown(field,1)) {
1253 form->curcol = 0;
1254 return(E_OK);
1256 #endif
1257 form->currow--;
1258 #if GROW_IF_NAVIGATE
1259 if (Single_Line_Field(field) && Field_Grown(field,1))
1260 return(E_OK);
1261 #endif
1262 form->curcol--;
1263 return(E_REQUEST_DENIED);
1265 form->curcol = 0;
1267 return(E_OK);
1270 /*---------------------------------------------------------------------------
1271 | Facility : libnform
1272 | Function : static int IFN_Previous_Character(FORM * form)
1274 | Description : Move to the previous character in the field. In a
1275 | multiline field this wraps and the beginning of the
1276 | line.
1278 | Return Values : E_OK - success
1279 | E_REQUEST_DENIED - at the leftmost position
1280 +--------------------------------------------------------------------------*/
1281 static int IFN_Previous_Character(FORM * form)
1283 if ((--(form->curcol))<0)
1285 if ((--(form->currow))<0)
1287 form->currow++;
1288 form->curcol++;
1289 return(E_REQUEST_DENIED);
1291 form->curcol = form->current->dcols - 1;
1293 return(E_OK);
1296 /*---------------------------------------------------------------------------
1297 | Facility : libnform
1298 | Function : static int IFN_Next_Line(FORM * form)
1300 | Description : Move to the beginning of the next line in the field
1302 | Return Values : E_OK - success
1303 | E_REQUEST_DENIED - at the last line
1304 +--------------------------------------------------------------------------*/
1305 static int IFN_Next_Line(FORM * form)
1307 FIELD *field = form->current;
1309 if ((++(form->currow))==field->drows)
1311 #if GROW_IF_NAVIGATE
1312 if (!Single_Line_Field(field) && Field_Grown(field,1))
1313 return(E_OK);
1314 #endif
1315 form->currow--;
1316 return(E_REQUEST_DENIED);
1318 form->curcol = 0;
1319 return(E_OK);
1322 /*---------------------------------------------------------------------------
1323 | Facility : libnform
1324 | Function : static int IFN_Previous_Line(FORM * form)
1326 | Description : Move to the beginning of the previous line in the field
1328 | Return Values : E_OK - success
1329 | E_REQUEST_DENIED - at the first line
1330 +--------------------------------------------------------------------------*/
1331 static int IFN_Previous_Line(FORM * form)
1333 if ( (--(form->currow)) < 0 )
1335 form->currow++;
1336 return(E_REQUEST_DENIED);
1338 form->curcol = 0;
1339 return(E_OK);
1342 /*---------------------------------------------------------------------------
1343 | Facility : libnform
1344 | Function : static int IFN_Next_Word(FORM * form)
1346 | Description : Move to the beginning of the next word in the field.
1348 | Return Values : E_OK - success
1349 | E_REQUEST_DENIED - there is no next word
1350 +--------------------------------------------------------------------------*/
1351 static int IFN_Next_Word(FORM * form)
1353 FIELD *field = form->current;
1354 char *bp = Address_Of_Current_Position_In_Buffer(form);
1355 char *s;
1356 char *t;
1358 /* We really need access to the data, so we have to synchronize */
1359 Synchronize_Buffer(form);
1361 /* Go to the first whitespace after the current position (including
1362 current position). This is then the startpoint to look for the
1363 next non-blank data */
1364 s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
1365 (int)(bp - field->buf));
1367 /* Find the start of the next word */
1368 t = Get_Start_Of_Data(s,Buffer_Length(field) -
1369 (int)(s - field->buf));
1370 #if !FRIENDLY_PREV_NEXT_WORD
1371 if (s==t)
1372 return(E_REQUEST_DENIED);
1373 else
1374 #endif
1376 Adjust_Cursor_Position(form,t);
1377 return(E_OK);
1381 /*---------------------------------------------------------------------------
1382 | Facility : libnform
1383 | Function : static int IFN_Previous_Word(FORM * form)
1385 | Description : Move to the beginning of the previous word in the field.
1387 | Return Values : E_OK - success
1388 | E_REQUEST_DENIED - there is no previous word
1389 +--------------------------------------------------------------------------*/
1390 static int IFN_Previous_Word(FORM * form)
1392 FIELD *field = form->current;
1393 char *bp = Address_Of_Current_Position_In_Buffer(form);
1394 char *s;
1395 char *t;
1396 bool again = FALSE;
1398 /* We really need access to the data, so we have to synchronize */
1399 Synchronize_Buffer(form);
1401 s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
1402 /* s points now right after the last non-blank in the buffer before bp.
1403 If bp was in a word, s equals bp. In this case we must find the last
1404 whitespace in the buffer before bp and repeat the game to really find
1405 the previous word! */
1406 if (s==bp)
1407 again = TRUE;
1409 /* And next call now goes backward to look for the last whitespace
1410 before that, pointing right after this, so it points to the begin
1411 of the previous word.
1413 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1414 #if !FRIENDLY_PREV_NEXT_WORD
1415 if (s==t)
1416 return(E_REQUEST_DENIED);
1417 #endif
1418 if (again)
1419 { /* and do it again, replacing bp by t */
1420 s = After_End_Of_Data(field->buf,(int)(t - field->buf));
1421 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1422 #if !FRIENDLY_PREV_NEXT_WORD
1423 if (s==t)
1424 return(E_REQUEST_DENIED);
1425 #endif
1427 Adjust_Cursor_Position(form,t);
1428 return(E_OK);
1431 /*---------------------------------------------------------------------------
1432 | Facility : libnform
1433 | Function : static int IFN_Beginning_Of_Field(FORM * form)
1435 | Description : Place the cursor at the first non-pad character in
1436 | the field.
1438 | Return Values : E_OK - success
1439 +--------------------------------------------------------------------------*/
1440 static int IFN_Beginning_Of_Field(FORM * form)
1442 FIELD *field = form->current;
1444 Synchronize_Buffer(form);
1445 Adjust_Cursor_Position(form,
1446 Get_Start_Of_Data(field->buf,Buffer_Length(field)));
1447 return(E_OK);
1450 /*---------------------------------------------------------------------------
1451 | Facility : libnform
1452 | Function : static int IFN_End_Of_Field(FORM * form)
1454 | Description : Place the cursor after the last non-pad character in
1455 | the field. If the field occupies the last position in
1456 | the buffer, the cursos is positioned on the last
1457 | character.
1459 | Return Values : E_OK - success
1460 +--------------------------------------------------------------------------*/
1461 static int IFN_End_Of_Field(FORM * form)
1463 FIELD *field = form->current;
1464 char *pos;
1466 Synchronize_Buffer(form);
1467 pos = After_End_Of_Data(field->buf,Buffer_Length(field));
1468 if (pos==(field->buf + Buffer_Length(field)))
1469 pos--;
1470 Adjust_Cursor_Position(form,pos);
1471 return(E_OK);
1474 /*---------------------------------------------------------------------------
1475 | Facility : libnform
1476 | Function : static int IFN_Beginning_Of_Line(FORM * form)
1478 | Description : Place the cursor on the first non-pad character in
1479 | the current line of the field.
1481 | Return Values : E_OK - success
1482 +--------------------------------------------------------------------------*/
1483 static int IFN_Beginning_Of_Line(FORM * form)
1485 FIELD *field = form->current;
1487 Synchronize_Buffer(form);
1488 Adjust_Cursor_Position(form,
1489 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1490 field->dcols));
1491 return(E_OK);
1494 /*---------------------------------------------------------------------------
1495 | Facility : libnform
1496 | Function : static int IFN_End_Of_Line(FORM * form)
1498 | Description : Place the cursor after the last non-pad character in the
1499 | current line of the field. If the field occupies the
1500 | last column in the line, the cursor is positioned on the
1501 | last character of the line.
1503 | Return Values : E_OK - success
1504 +--------------------------------------------------------------------------*/
1505 static int IFN_End_Of_Line(FORM * form)
1507 FIELD *field = form->current;
1508 char *pos;
1509 char *bp;
1511 Synchronize_Buffer(form);
1512 bp = Address_Of_Current_Row_In_Buffer(form);
1513 pos = After_End_Of_Data(bp,field->dcols);
1514 if (pos == (bp + field->dcols))
1515 pos--;
1516 Adjust_Cursor_Position(form,pos);
1517 return(E_OK);
1520 /*---------------------------------------------------------------------------
1521 | Facility : libnform
1522 | Function : static int IFN_Left_Character(FORM * form)
1524 | Description : Move one character to the left in the current line.
1525 | This doesn't cycle.
1527 | Return Values : E_OK - success
1528 | E_REQUEST_DENIED - already in first column
1529 +--------------------------------------------------------------------------*/
1530 static int IFN_Left_Character(FORM * form)
1532 if ( (--(form->curcol)) < 0 )
1534 form->curcol++;
1535 return(E_REQUEST_DENIED);
1537 return(E_OK);
1540 /*---------------------------------------------------------------------------
1541 | Facility : libnform
1542 | Function : static int IFN_Right_Character(FORM * form)
1544 | Description : Move one character to the right in the current line.
1545 | This doesn't cycle.
1547 | Return Values : E_OK - success
1548 | E_REQUEST_DENIED - already in last column
1549 +--------------------------------------------------------------------------*/
1550 static int IFN_Right_Character(FORM * form)
1552 if ( (++(form->curcol)) == form->current->dcols )
1554 #if GROW_IF_NAVIGATE
1555 FIELD *field = form->current;
1556 if (Single_Line_Field(field) && Field_Grown(field,1))
1557 return(E_OK);
1558 #endif
1559 --(form->curcol);
1560 return(E_REQUEST_DENIED);
1562 return(E_OK);
1565 /*---------------------------------------------------------------------------
1566 | Facility : libnform
1567 | Function : static int IFN_Up_Character(FORM * form)
1569 | Description : Move one line up. This doesn't cycle through the lines
1570 | of the field.
1572 | Return Values : E_OK - success
1573 | E_REQUEST_DENIED - already in last column
1574 +--------------------------------------------------------------------------*/
1575 static int IFN_Up_Character(FORM * form)
1577 if ( (--(form->currow)) < 0 )
1579 form->currow++;
1580 return(E_REQUEST_DENIED);
1582 return(E_OK);
1585 /*---------------------------------------------------------------------------
1586 | Facility : libnform
1587 | Function : static int IFN_Down_Character(FORM * form)
1589 | Description : Move one line down. This doesn't cycle through the
1590 | lines of the field.
1592 | Return Values : E_OK - success
1593 | E_REQUEST_DENIED - already in last column
1594 +--------------------------------------------------------------------------*/
1595 static int IFN_Down_Character(FORM * form)
1597 FIELD *field = form->current;
1599 if ( (++(form->currow)) == field->drows )
1601 #if GROW_IF_NAVIGATE
1602 if (!Single_Line_Field(field) && Field_Grown(field,1))
1603 return(E_OK);
1604 #endif
1605 --(form->currow);
1606 return(E_REQUEST_DENIED);
1608 return(E_OK);
1610 /*----------------------------------------------------------------------------
1611 END of Intra-Field Navigation routines
1612 --------------------------------------------------------------------------*/
1614 /*----------------------------------------------------------------------------
1615 Vertical scrolling helper routines
1616 --------------------------------------------------------------------------*/
1618 /*---------------------------------------------------------------------------
1619 | Facility : libnform
1620 | Function : static int VSC_Generic(FORM *form, int lines)
1622 | Description : Scroll multi-line field forward (lines>0) or
1623 | backward (lines<0) this many lines.
1625 | Return Values : E_OK - success
1626 | E_REQUEST_DENIED - can't scroll
1627 +--------------------------------------------------------------------------*/
1628 static int VSC_Generic(FORM *form, int lines)
1630 FIELD *field = form->current;
1631 int res = E_REQUEST_DENIED;
1632 int rows_to_go = (lines > 0 ? lines : -lines);
1634 if (lines > 0)
1636 if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
1637 rows_to_go = (field->drows - field->rows - form->toprow);
1639 if (rows_to_go > 0)
1641 form->currow += rows_to_go;
1642 form->toprow += rows_to_go;
1643 res = E_OK;
1646 else
1648 if (rows_to_go > form->toprow)
1649 rows_to_go = form->toprow;
1651 if (rows_to_go > 0)
1653 form->currow -= rows_to_go;
1654 form->toprow -= rows_to_go;
1655 res = E_OK;
1658 return(res);
1660 /*----------------------------------------------------------------------------
1661 End of Vertical scrolling helper routines
1662 --------------------------------------------------------------------------*/
1664 /*----------------------------------------------------------------------------
1665 Vertical scrolling routines
1666 --------------------------------------------------------------------------*/
1668 /*---------------------------------------------------------------------------
1669 | Facility : libnform
1670 | Function : static int Vertical_Scrolling(
1671 | int (* const fct) (FORM *),
1672 | FORM * form)
1674 | Description : Performs the generic vertical scrolling routines.
1675 | This has to check for a multi-line field and to set
1676 | the _NEWTOP flag if scrolling really occured.
1678 | Return Values : Propagated error code from low-level driver calls
1679 +--------------------------------------------------------------------------*/
1680 static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
1682 int res = E_REQUEST_DENIED;
1684 if (!Single_Line_Field(form->current))
1686 res = fct(form);
1687 if (res == E_OK)
1688 form->current->status |= _NEWTOP;
1690 return(res);
1693 /*---------------------------------------------------------------------------
1694 | Facility : libnform
1695 | Function : static int VSC_Scroll_Line_Forward(FORM * form)
1697 | Description : Scroll multi-line field forward a line
1699 | Return Values : E_OK - success
1700 | E_REQUEST_DENIED - no data ahead
1701 +--------------------------------------------------------------------------*/
1702 static int VSC_Scroll_Line_Forward(FORM * form)
1704 return VSC_Generic(form,1);
1707 /*---------------------------------------------------------------------------
1708 | Facility : libnform
1709 | Function : static int VSC_Scroll_Line_Backward(FORM * form)
1711 | Description : Scroll multi-line field backward a line
1713 | Return Values : E_OK - success
1714 | E_REQUEST_DENIED - no data behind
1715 +--------------------------------------------------------------------------*/
1716 static int VSC_Scroll_Line_Backward(FORM * form)
1718 return VSC_Generic(form,-1);
1721 /*---------------------------------------------------------------------------
1722 | Facility : libnform
1723 | Function : static int VSC_Scroll_Page_Forward(FORM * form)
1725 | Description : Scroll a multi-line field forward a page
1727 | Return Values : E_OK - success
1728 | E_REQUEST_DENIED - no data ahead
1729 +--------------------------------------------------------------------------*/
1730 static int VSC_Scroll_Page_Forward(FORM * form)
1732 return VSC_Generic(form,form->current->rows);
1735 /*---------------------------------------------------------------------------
1736 | Facility : libnform
1737 | Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1739 | Description : Scroll a multi-line field forward half a page
1741 | Return Values : E_OK - success
1742 | E_REQUEST_DENIED - no data ahead
1743 +--------------------------------------------------------------------------*/
1744 static int VSC_Scroll_Half_Page_Forward(FORM * form)
1746 return VSC_Generic(form,(form->current->rows + 1)/2);
1749 /*---------------------------------------------------------------------------
1750 | Facility : libnform
1751 | Function : static int VSC_Scroll_Page_Backward(FORM * form)
1753 | Description : Scroll a multi-line field backward a page
1755 | Return Values : E_OK - success
1756 | E_REQUEST_DENIED - no data behind
1757 +--------------------------------------------------------------------------*/
1758 static int VSC_Scroll_Page_Backward(FORM * form)
1760 return VSC_Generic(form, -(form->current->rows));
1763 /*---------------------------------------------------------------------------
1764 | Facility : libnform
1765 | Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
1767 | Description : Scroll a multi-line field backward half a page
1769 | Return Values : E_OK - success
1770 | E_REQUEST_DENIED - no data behind
1771 +--------------------------------------------------------------------------*/
1772 static int VSC_Scroll_Half_Page_Backward(FORM * form)
1774 return VSC_Generic(form, -((form->current->rows + 1)/2));
1776 /*----------------------------------------------------------------------------
1777 End of Vertical scrolling routines
1778 --------------------------------------------------------------------------*/
1780 /*----------------------------------------------------------------------------
1781 Horizontal scrolling helper routines
1782 --------------------------------------------------------------------------*/
1784 /*---------------------------------------------------------------------------
1785 | Facility : libnform
1786 | Function : static int HSC_Generic(FORM *form, int columns)
1788 | Description : Scroll single-line field forward (columns>0) or
1789 | backward (columns<0) this many columns.
1791 | Return Values : E_OK - success
1792 | E_REQUEST_DENIED - can't scroll
1793 +--------------------------------------------------------------------------*/
1794 static int HSC_Generic(FORM *form, int columns)
1796 FIELD *field = form->current;
1797 int res = E_REQUEST_DENIED;
1798 int cols_to_go = (columns > 0 ? columns : -columns);
1800 if (columns > 0)
1802 if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
1803 cols_to_go = field->dcols - field->cols - form->begincol;
1805 if (cols_to_go > 0)
1807 form->curcol += cols_to_go;
1808 form->begincol += cols_to_go;
1809 res = E_OK;
1812 else
1814 if ( cols_to_go > form->begincol )
1815 cols_to_go = form->begincol;
1817 if (cols_to_go > 0)
1819 form->curcol -= cols_to_go;
1820 form->begincol -= cols_to_go;
1821 res = E_OK;
1824 return(res);
1826 /*----------------------------------------------------------------------------
1827 End of Horizontal scrolling helper routines
1828 --------------------------------------------------------------------------*/
1830 /*----------------------------------------------------------------------------
1831 Horizontal scrolling routines
1832 --------------------------------------------------------------------------*/
1834 /*---------------------------------------------------------------------------
1835 | Facility : libnform
1836 | Function : static int Horizontal_Scrolling(
1837 | int (* const fct) (FORM *),
1838 | FORM * form)
1840 | Description : Performs the generic horizontal scrolling routines.
1841 | This has to check for a single-line field.
1843 | Return Values : Propagated error code from low-level driver calls
1844 +--------------------------------------------------------------------------*/
1845 static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
1847 if (Single_Line_Field(form->current))
1848 return fct(form);
1849 else
1850 return(E_REQUEST_DENIED);
1853 /*---------------------------------------------------------------------------
1854 | Facility : libnform
1855 | Function : static int HSC_Scroll_Char_Forward(FORM * form)
1857 | Description : Scroll single-line field forward a character
1859 | Return Values : E_OK - success
1860 | E_REQUEST_DENIED - no data ahead
1861 +--------------------------------------------------------------------------*/
1862 static int HSC_Scroll_Char_Forward(FORM *form)
1864 return HSC_Generic(form,1);
1867 /*---------------------------------------------------------------------------
1868 | Facility : libnform
1869 | Function : static int HSC_Scroll_Char_Backward(FORM * form)
1871 | Description : Scroll single-line field backward a character
1873 | Return Values : E_OK - success
1874 | E_REQUEST_DENIED - no data behind
1875 +--------------------------------------------------------------------------*/
1876 static int HSC_Scroll_Char_Backward(FORM *form)
1878 return HSC_Generic(form,-1);
1881 /*---------------------------------------------------------------------------
1882 | Facility : libnform
1883 | Function : static int HSC_Horizontal_Line_Forward(FORM* form)
1885 | Description : Scroll single-line field forward a line
1887 | Return Values : E_OK - success
1888 | E_REQUEST_DENIED - no data ahead
1889 +--------------------------------------------------------------------------*/
1890 static int HSC_Horizontal_Line_Forward(FORM * form)
1892 return HSC_Generic(form,form->current->cols);
1895 /*---------------------------------------------------------------------------
1896 | Facility : libnform
1897 | Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
1899 | Description : Scroll single-line field forward half a line
1901 | Return Values : E_OK - success
1902 | E_REQUEST_DENIED - no data ahead
1903 +--------------------------------------------------------------------------*/
1904 static int HSC_Horizontal_Half_Line_Forward(FORM * form)
1906 return HSC_Generic(form,(form->current->cols + 1)/2);
1909 /*---------------------------------------------------------------------------
1910 | Facility : libnform
1911 | Function : static int HSC_Horizontal_Line_Backward(FORM* form)
1913 | Description : Scroll single-line field backward a line
1915 | Return Values : E_OK - success
1916 | E_REQUEST_DENIED - no data behind
1917 +--------------------------------------------------------------------------*/
1918 static int HSC_Horizontal_Line_Backward(FORM * form)
1920 return HSC_Generic(form,-(form->current->cols));
1923 /*---------------------------------------------------------------------------
1924 | Facility : libnform
1925 | Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
1927 | Description : Scroll single-line field backward half a line
1929 | Return Values : E_OK - success
1930 | E_REQUEST_DENIED - no data behind
1931 +--------------------------------------------------------------------------*/
1932 static int HSC_Horizontal_Half_Line_Backward(FORM * form)
1934 return HSC_Generic(form,-((form->current->cols + 1)/2));
1937 /*----------------------------------------------------------------------------
1938 End of Horizontal scrolling routines
1939 --------------------------------------------------------------------------*/
1941 /*----------------------------------------------------------------------------
1942 Helper routines for Field Editing
1943 --------------------------------------------------------------------------*/
1945 /*---------------------------------------------------------------------------
1946 | Facility : libnform
1947 | Function : static bool Is_There_Room_For_A_Line(FORM * form)
1949 | Description : Check whether or not there is enough room in the
1950 | buffer to enter a whole line.
1952 | Return Values : TRUE - there is enough space
1953 | FALSE - there is not enough space
1954 +--------------------------------------------------------------------------*/
1955 INLINE static bool Is_There_Room_For_A_Line(FORM * form)
1957 FIELD *field = form->current;
1958 char *begin_of_last_line, *s;
1960 Synchronize_Buffer(form);
1961 begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
1962 s = After_End_Of_Data(begin_of_last_line,field->dcols);
1963 return ((s==begin_of_last_line) ? TRUE : FALSE);
1966 /*---------------------------------------------------------------------------
1967 | Facility : libnform
1968 | Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1970 | Description : Checks whether or not there is room for a new character
1971 | in the current line.
1973 | Return Values : TRUE - there is room
1974 | FALSE - there is not enough room (line full)
1975 +--------------------------------------------------------------------------*/
1976 INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1978 int last_char_in_line;
1980 wmove(form->w,form->currow,form->current->dcols-1);
1981 last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
1982 wmove(form->w,form->currow,form->curcol);
1983 return (((last_char_in_line == form->current->pad) ||
1984 is_blank(last_char_in_line)) ? TRUE : FALSE);
1987 #define There_Is_No_Room_For_A_Char_In_Line(f) \
1988 !Is_There_Room_For_A_Char_In_Line(f)
1990 /*---------------------------------------------------------------------------
1991 | Facility : libnform
1992 | Function : static int Insert_String(
1993 | FORM * form,
1994 | int row,
1995 | char *txt,
1996 | int len )
1998 | Description : Insert the 'len' characters beginning at pointer 'txt'
1999 | into the 'row' of the 'form'. The insertion occurs
2000 | on the beginning of the row, all other characters are
2001 | moved to the right. After the text a pad character will
2002 | be inserted to separate the text from the rest. If
2003 | necessary the insertion moves characters on the next
2004 | line to make place for the requested insertion string.
2006 | Return Values : E_OK - success
2007 | E_REQUEST_DENIED -
2008 | E_SYSTEM_ERROR - system error
2009 +--------------------------------------------------------------------------*/
2010 static int Insert_String(FORM *form, int row, char *txt, int len)
2012 FIELD *field = form->current;
2013 char *bp = Address_Of_Row_In_Buffer(field,row);
2014 int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
2015 int freelen = field->dcols - datalen;
2016 int requiredlen = len+1;
2017 char *split;
2018 int result = E_REQUEST_DENIED;
2019 char *Space;
2021 Space = (char*)malloc(2*sizeof(char));
2022 strcpy(Space, " ");
2024 if (freelen >= requiredlen)
2026 wmove(form->w,row,0);
2027 winsnstr(form->w,txt,len);
2028 wmove(form->w,row,len);
2029 winsnstr(form->w,Space,1);
2030 free(Space);
2031 return E_OK;
2033 else
2034 { /* we have to move characters on the next line. If we are on the
2035 last line this may work, if the field is growable */
2036 if ((row == (field->drows - 1)) && Growable(field))
2038 if (!Field_Grown(field,1))
2040 free(Space);
2041 return(E_SYSTEM_ERROR);
2043 /* !!!Side-Effect : might be changed due to growth!!! */
2044 bp = Address_Of_Row_In_Buffer(field,row);
2047 if (row < (field->drows - 1))
2049 split = After_Last_Whitespace_Character(bp,
2050 (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
2051 requiredlen) - bp));
2052 /* split points now to the first character of the portion of the
2053 line that must be moved to the next line */
2054 datalen = (int)(split-bp); /* + freelen has to stay on this line */
2055 freelen = field->dcols - (datalen + freelen); /* for the next line */
2057 if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
2059 wmove(form->w,row,datalen);
2060 wclrtoeol(form->w);
2061 wmove(form->w,row,0);
2062 winsnstr(form->w,txt,len);
2063 wmove(form->w,row,len);
2064 winsnstr(form->w,Space,1);
2065 free(Space);
2066 return E_OK;
2069 free(Space);
2070 return(result);
2074 /*---------------------------------------------------------------------------
2075 | Facility : libnform
2076 | Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2077 | FORM * form)
2079 | Description : If a character has been entered into a field, it may
2080 | be that wrapping has to occur. This routine checks
2081 | whether or not wrapping is required and if so, performs
2082 | the wrapping.
2084 | Return Values : E_OK - no wrapping required or wrapping
2085 | was successfull
2086 | E_REQUEST_DENIED -
2087 | E_SYSTEM_ERROR - some system error
2088 +--------------------------------------------------------------------------*/
2089 static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
2091 FIELD *field = form->current;
2092 int result = E_REQUEST_DENIED;
2093 bool Last_Row = ((field->drows - 1) == form->currow);
2095 if ( (field->opts & O_WRAP) && /* wrapping wanted */
2096 (!Single_Line_Field(field)) && /* must be multi-line */
2097 (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
2098 (!Last_Row || Growable(field)) ) /* there are more lines*/
2100 char *bp;
2101 char *split;
2102 int chars_to_be_wrapped;
2103 int chars_to_remain_on_line;
2104 if (Last_Row)
2105 { /* the above logic already ensures, that in this case the field
2106 is growable */
2107 if (!Field_Grown(field,1))
2108 return E_SYSTEM_ERROR;
2110 bp = Address_Of_Current_Row_In_Buffer(form);
2111 Window_To_Buffer(form->w,field);
2112 split = After_Last_Whitespace_Character(bp,field->dcols);
2113 /* split points to the first character of the sequence to be brought
2114 on the next line */
2115 chars_to_remain_on_line = (int)(split - bp);
2116 chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2117 if (chars_to_remain_on_line > 0)
2119 if ((result=Insert_String(form,form->currow+1,split,
2120 chars_to_be_wrapped)) == E_OK)
2122 wmove(form->w,form->currow,chars_to_remain_on_line);
2123 wclrtoeol(form->w);
2124 if (form->curcol >= chars_to_remain_on_line)
2126 form->currow++;
2127 form->curcol -= chars_to_remain_on_line;
2129 return E_OK;
2132 else
2133 return E_OK;
2134 if (result!=E_OK)
2136 wmove(form->w,form->currow,form->curcol);
2137 wdelch(form->w);
2138 Window_To_Buffer(form->w,field);
2139 result = E_REQUEST_DENIED;
2142 else
2143 result = E_OK; /* wrapping was not necessary */
2144 return(result);
2147 /*----------------------------------------------------------------------------
2148 Field Editing routines
2149 --------------------------------------------------------------------------*/
2151 /*---------------------------------------------------------------------------
2152 | Facility : libnform
2153 | Function : static int Field_Editing(
2154 | int (* const fct) (FORM *),
2155 | FORM * form)
2157 | Description : Generic routine for field editing requests. The driver
2158 | routines are only called for editable fields, the
2159 | _WINDOW_MODIFIED flag is set if editing occured.
2160 | This is somewhat special due to the overload semantics
2161 | of the NEW_LINE and DEL_PREV requests.
2163 | Return Values : Error code from low level drivers.
2164 +--------------------------------------------------------------------------*/
2165 static int Field_Editing(int (* const fct) (FORM *), FORM * form)
2167 int res = E_REQUEST_DENIED;
2169 /* We have to deal here with the specific case of the overloaded
2170 behaviour of New_Line and Delete_Previous requests.
2171 They may end up in navigational requests if we are on the first
2172 character in a field. But navigation is also allowed on non-
2173 editable fields.
2175 if ((fct==FE_Delete_Previous) &&
2176 (form->opts & O_BS_OVERLOAD) &&
2177 First_Position_In_Current_Field(form) )
2179 res = Inter_Field_Navigation(FN_Previous_Field,form);
2181 else
2183 if (fct==FE_New_Line)
2185 if ((form->opts & O_NL_OVERLOAD) &&
2186 First_Position_In_Current_Field(form))
2188 res = Inter_Field_Navigation(FN_Next_Field,form);
2190 else
2191 /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2192 res = fct(form);
2194 else
2196 /* From now on, everything must be editable */
2197 if (form->current->opts & O_EDIT)
2199 res = fct(form);
2200 if (res==E_OK)
2201 form->status |= _WINDOW_MODIFIED;
2205 return res;
2208 /*---------------------------------------------------------------------------
2209 | Facility : libnform
2210 | Function : static int FE_New_Line(FORM * form)
2212 | Description : Perform a new line request. This is rather complex
2213 | compared to other routines in this code due to the
2214 | rather difficult to understand description in the
2215 | manuals.
2217 | Return Values : E_OK - success
2218 | E_REQUEST_DENIED - new line not allowed
2219 | E_SYSTEM_ERROR - system error
2220 +--------------------------------------------------------------------------*/
2221 static int FE_New_Line(FORM * form)
2223 FIELD *field = form->current;
2224 char *bp, *t;
2225 bool Last_Row = ((field->drows - 1)==form->currow);
2227 if (form->status & _OVLMODE)
2229 if (Last_Row &&
2230 (!(Growable(field) && !Single_Line_Field(field))))
2232 if (!(form->opts & O_NL_OVERLOAD))
2233 return(E_REQUEST_DENIED);
2234 wclrtoeol(form->w);
2235 /* we have to set this here, although it is also
2236 handled in the generic routine. The reason is,
2237 that FN_Next_Field may fail, but the form is
2238 definitively changed */
2239 form->status |= _WINDOW_MODIFIED;
2240 return Inter_Field_Navigation(FN_Next_Field,form);
2242 else
2244 if (Last_Row && !Field_Grown(field,1))
2245 { /* N.B.: due to the logic in the 'if', LastRow==TRUE
2246 means here that the field is growable and not
2247 a single-line field */
2248 return(E_SYSTEM_ERROR);
2250 wclrtoeol(form->w);
2251 form->currow++;
2252 form->curcol = 0;
2253 form->status |= _WINDOW_MODIFIED;
2254 return(E_OK);
2257 else
2258 { /* Insert Mode */
2259 if (Last_Row &&
2260 !(Growable(field) && !Single_Line_Field(field)))
2262 if (!(form->opts & O_NL_OVERLOAD))
2263 return(E_REQUEST_DENIED);
2264 return Inter_Field_Navigation(FN_Next_Field,form);
2266 else
2268 bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2270 if (!(May_Do_It || Growable(field)))
2271 return(E_REQUEST_DENIED);
2272 if (!May_Do_It && !Field_Grown(field,1))
2273 return(E_SYSTEM_ERROR);
2275 bp= Address_Of_Current_Position_In_Buffer(form);
2276 t = After_End_Of_Data(bp,field->dcols - form->curcol);
2277 wclrtoeol(form->w);
2278 form->currow++;
2279 form->curcol=0;
2280 wmove(form->w,form->currow,form->curcol);
2281 winsertln(form->w);
2282 waddnstr(form->w,bp,(int)(t-bp));
2283 form->status |= _WINDOW_MODIFIED;
2284 return E_OK;
2289 /*---------------------------------------------------------------------------
2290 | Facility : libnform
2291 | Function : static int FE_Insert_Character(FORM * form)
2293 | Description : Insert blank character at the cursor position
2295 | Return Values : E_OK
2296 | E_REQUEST_DENIED
2297 +--------------------------------------------------------------------------*/
2298 static int FE_Insert_Character(FORM * form)
2300 FIELD *field = form->current;
2301 int result = E_REQUEST_DENIED;
2303 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2305 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2307 if (There_Is_Room ||
2308 ((Single_Line_Field(field) && Growable(field))))
2310 if (!There_Is_Room && !Field_Grown(field,1))
2311 result = E_SYSTEM_ERROR;
2312 else
2314 winsch(form->w,(chtype)C_BLANK);
2315 result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2319 return result;
2322 /*---------------------------------------------------------------------------
2323 | Facility : libnform
2324 | Function : static int FE_Insert_Line(FORM * form)
2326 | Description : Insert a blank line at the cursor position
2328 | Return Values : E_OK - success
2329 | E_REQUEST_DENIED - line can not be inserted
2330 +--------------------------------------------------------------------------*/
2331 static int FE_Insert_Line(FORM * form)
2333 FIELD *field = form->current;
2334 int result = E_REQUEST_DENIED;
2336 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2338 bool Maybe_Done = (form->currow!=(field->drows-1)) &&
2339 Is_There_Room_For_A_Line(form);
2341 if (!Single_Line_Field(field) &&
2342 (Maybe_Done || Growable(field)))
2344 if (!Maybe_Done && !Field_Grown(field,1))
2345 result = E_SYSTEM_ERROR;
2346 else
2348 form->curcol = 0;
2349 winsertln(form->w);
2350 result = E_OK;
2354 return result;
2357 /*---------------------------------------------------------------------------
2358 | Facility : libnform
2359 | Function : static int FE_Delete_Character(FORM * form)
2361 | Description : Delete character at the cursor position
2363 | Return Values : E_OK - success
2364 +--------------------------------------------------------------------------*/
2365 static int FE_Delete_Character(FORM * form)
2367 wdelch(form->w);
2368 return E_OK;
2371 /*---------------------------------------------------------------------------
2372 | Facility : libnform
2373 | Function : static int FE_Delete_Previous(FORM * form)
2375 | Description : Delete character before cursor. Again this is a rather
2376 | difficult piece compared to others due to the overloading
2377 | semantics of backspace.
2378 | N.B.: The case of overloaded BS on first field position
2379 | is already handled in the generic routine.
2381 | Return Values : E_OK - success
2382 | E_REQUEST_DENIED - Character can't be deleted
2383 +--------------------------------------------------------------------------*/
2384 static int FE_Delete_Previous(FORM * form)
2386 FIELD *field = form->current;
2388 if (First_Position_In_Current_Field(form))
2389 return E_REQUEST_DENIED;
2391 if ( (--(form->curcol))<0 )
2393 char *this_line, *prev_line, *prev_end, *this_end;
2395 form->curcol++;
2396 if (form->status & _OVLMODE)
2397 return E_REQUEST_DENIED;
2399 prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
2400 this_line = Address_Of_Row_In_Buffer(field,(form->currow));
2401 Synchronize_Buffer(form);
2402 prev_end = After_End_Of_Data(prev_line,field->dcols);
2403 this_end = After_End_Of_Data(this_line,field->dcols);
2404 if ((int)(this_end-this_line) >
2405 (field->cols-(int)(prev_end-prev_line)))
2406 return E_REQUEST_DENIED;
2407 wdeleteln(form->w);
2408 Adjust_Cursor_Position(form,prev_end);
2409 wmove(form->w,form->currow,form->curcol);
2410 waddnstr(form->w,this_line,(int)(this_end-this_line));
2412 else
2414 wmove(form->w,form->currow,form->curcol);
2415 wdelch(form->w);
2417 return E_OK;
2420 /*---------------------------------------------------------------------------
2421 | Facility : libnform
2422 | Function : static int FE_Delete_Line(FORM * form)
2424 | Description : Delete line at cursor position.
2426 | Return Values : E_OK - success
2427 +--------------------------------------------------------------------------*/
2428 static int FE_Delete_Line(FORM * form)
2430 form->curcol = 0;
2431 wdeleteln(form->w);
2432 return E_OK;
2435 /*---------------------------------------------------------------------------
2436 | Facility : libnform
2437 | Function : static int FE_Delete_Word(FORM * form)
2439 | Description : Delete word at cursor position
2441 | Return Values : E_OK - success
2442 | E_REQUEST_DENIED - failure
2443 +--------------------------------------------------------------------------*/
2444 static int FE_Delete_Word(FORM * form)
2446 FIELD *field = form->current;
2447 char *bp = Address_Of_Current_Row_In_Buffer(form);
2448 char *ep = bp + field->dcols;
2449 char *cp = bp + form->curcol;
2450 char *s;
2452 Synchronize_Buffer(form);
2453 if (is_blank(*cp))
2454 return E_REQUEST_DENIED; /* not in word */
2456 /* move cursor to begin of word and erase to end of screen-line */
2457 Adjust_Cursor_Position(form,
2458 After_Last_Whitespace_Character(bp,form->curcol));
2459 wmove(form->w,form->currow,form->curcol);
2460 wclrtoeol(form->w);
2462 /* skip over word in buffer */
2463 s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
2464 /* to begin of next word */
2465 s = Get_Start_Of_Data(s,(int)(ep - s));
2466 if ( (s!=cp) && !is_blank(*s))
2468 /* copy remaining line to window */
2469 waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
2471 return E_OK;
2474 /*---------------------------------------------------------------------------
2475 | Facility : libnform
2476 | Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2478 | Description : Clear to end of current line.
2480 | Return Values : E_OK - success
2481 +--------------------------------------------------------------------------*/
2482 static int FE_Clear_To_End_Of_Line(FORM * form)
2484 wclrtoeol(form->w);
2485 return E_OK;
2488 /*---------------------------------------------------------------------------
2489 | Facility : libnform
2490 | Function : static int FE_Clear_To_End_Of_Form(FORM * form)
2492 | Description : Clear to end of form.
2494 | Return Values : E_OK - success
2495 +--------------------------------------------------------------------------*/
2496 static int FE_Clear_To_End_Of_Form(FORM * form)
2498 wclrtobot(form->w);
2499 return E_OK;
2502 /*---------------------------------------------------------------------------
2503 | Facility : libnform
2504 | Function : static int FE_Clear_Field(FORM * form)
2506 | Description : Clear entire field.
2508 | Return Values : E_OK - success
2509 +--------------------------------------------------------------------------*/
2510 static int FE_Clear_Field(FORM * form)
2512 form->currow = form->curcol = 0;
2513 werase(form->w);
2514 return E_OK;
2516 /*----------------------------------------------------------------------------
2517 END of Field Editing routines
2518 --------------------------------------------------------------------------*/
2520 /*----------------------------------------------------------------------------
2521 Edit Mode routines
2522 --------------------------------------------------------------------------*/
2524 /*---------------------------------------------------------------------------
2525 | Facility : libnform
2526 | Function : static int EM_Overlay_Mode(FORM * form)
2528 | Description : Switch to overlay mode.
2530 | Return Values : E_OK - success
2531 +--------------------------------------------------------------------------*/
2532 static int EM_Overlay_Mode(FORM * form)
2534 form->status |= _OVLMODE;
2535 return E_OK;
2538 /*---------------------------------------------------------------------------
2539 | Facility : libnform
2540 | Function : static int EM_Insert_Mode(FORM * form)
2542 | Description : Switch to insert mode
2544 | Return Values : E_OK - success
2545 +--------------------------------------------------------------------------*/
2546 static int EM_Insert_Mode(FORM * form)
2548 form->status &= ~_OVLMODE;
2549 return E_OK;
2552 /*----------------------------------------------------------------------------
2553 END of Edit Mode routines
2554 --------------------------------------------------------------------------*/
2556 /*----------------------------------------------------------------------------
2557 Helper routines for Choice Requests
2558 --------------------------------------------------------------------------*/
2560 /*---------------------------------------------------------------------------
2561 | Facility : libnform
2562 | Function : static bool Next_Choice(
2563 | FIELDTYPE * typ,
2564 | FIELD * field,
2565 | TypeArgument *argp)
2567 | Description : Get the next field choice. For linked types this is
2568 | done recursively.
2570 | Return Values : TRUE - next choice successfully retrieved
2571 | FALSE - couldn't retrieve next choice
2572 +--------------------------------------------------------------------------*/
2573 static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
2575 if (!typ || !(typ->status & _HAS_CHOICE))
2576 return FALSE;
2578 if (typ->status & _LINKED_TYPE)
2580 assert(argp != 0);
2581 return(
2582 Next_Choice(typ->left ,field,argp->left) ||
2583 Next_Choice(typ->right,field,argp->right) );
2585 else
2587 assert(typ->next != 0);
2588 return typ->next(field,(void *)argp);
2592 /*---------------------------------------------------------------------------
2593 | Facility : libnform
2594 | Function : static bool Previous_Choice(
2595 | FIELDTYPE * typ,
2596 | FIELD * field,
2597 | TypeArgument *argp)
2599 | Description : Get the previous field choice. For linked types this
2600 | is done recursively.
2602 | Return Values : TRUE - previous choice successfully retrieved
2603 | FALSE - couldn't retrieve previous choice
2604 +--------------------------------------------------------------------------*/
2605 static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2607 if (!typ || !(typ->status & _HAS_CHOICE))
2608 return FALSE;
2610 if (typ->status & _LINKED_TYPE)
2612 assert(argp != 0);
2613 return(
2614 Previous_Choice(typ->left ,field,argp->left) ||
2615 Previous_Choice(typ->right,field,argp->right));
2617 else
2619 assert(typ->prev != 0);
2620 return typ->prev(field,(void *)argp);
2623 /*----------------------------------------------------------------------------
2624 End of Helper routines for Choice Requests
2625 --------------------------------------------------------------------------*/
2627 /*----------------------------------------------------------------------------
2628 Routines for Choice Requests
2629 --------------------------------------------------------------------------*/
2631 /*---------------------------------------------------------------------------
2632 | Facility : libnform
2633 | Function : static int CR_Next_Choice(FORM * form)
2635 | Description : Get the next field choice.
2637 | Return Values : E_OK - success
2638 | E_REQUEST_DENIED - next choice couldn't be retrieved
2639 +--------------------------------------------------------------------------*/
2640 static int CR_Next_Choice(FORM * form)
2642 FIELD *field = form->current;
2643 Synchronize_Buffer(form);
2644 return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2645 E_OK : E_REQUEST_DENIED);
2648 /*---------------------------------------------------------------------------
2649 | Facility : libnform
2650 | Function : static int CR_Previous_Choice(FORM * form)
2652 | Description : Get the previous field choice.
2654 | Return Values : E_OK - success
2655 | E_REQUEST_DENIED - prev. choice couldn't be retrieved
2656 +--------------------------------------------------------------------------*/
2657 static int CR_Previous_Choice(FORM * form)
2659 FIELD *field = form->current;
2660 Synchronize_Buffer(form);
2661 return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2662 E_OK : E_REQUEST_DENIED);
2664 /*----------------------------------------------------------------------------
2665 End of Routines for Choice Requests
2666 --------------------------------------------------------------------------*/
2668 /*----------------------------------------------------------------------------
2669 Helper routines for Field Validations.
2670 --------------------------------------------------------------------------*/
2672 /*---------------------------------------------------------------------------
2673 | Facility : libnform
2674 | Function : static bool Check_Field(
2675 | FIELDTYPE * typ,
2676 | FIELD * field,
2677 | TypeArgument * argp)
2679 | Description : Check the field according to its fieldtype and its
2680 | actual arguments. For linked fieldtypes this is done
2681 | recursively.
2683 | Return Values : TRUE - field is valid
2684 | FALSE - field is invalid.
2685 +--------------------------------------------------------------------------*/
2686 static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2688 if (typ)
2690 if (field->opts & O_NULLOK)
2692 char *bp = field->buf;
2693 assert(bp != 0);
2694 while(is_blank(*bp))
2695 { bp++; }
2696 if (*bp == '\0')
2697 return TRUE;
2700 if (typ->status & _LINKED_TYPE)
2702 assert(argp != 0);
2703 return(
2704 Check_Field(typ->left ,field,argp->left ) ||
2705 Check_Field(typ->right,field,argp->right) );
2707 else
2709 if (typ->fcheck)
2710 return typ->fcheck(field,(void *)argp);
2713 return TRUE;
2716 /*---------------------------------------------------------------------------
2717 | Facility : libnform
2718 | Function : bool _nc_Internal_Validation(FORM * form )
2720 | Description : Validate the current field of the form.
2722 | Return Values : TRUE - field is valid
2723 | FALSE - field is invalid
2724 +--------------------------------------------------------------------------*/
2725 bool
2726 _nc_Internal_Validation(FORM *form)
2728 FIELD *field;
2730 field = form->current;
2732 Synchronize_Buffer(form);
2733 if ((form->status & _FCHECK_REQUIRED) ||
2734 (!(field->opts & O_PASSOK)))
2736 if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
2737 return FALSE;
2738 form->status &= ~_FCHECK_REQUIRED;
2739 field->status |= _CHANGED;
2740 Synchronize_Linked_Fields(field);
2742 return TRUE;
2744 /*----------------------------------------------------------------------------
2745 End of Helper routines for Field Validations.
2746 --------------------------------------------------------------------------*/
2748 /*----------------------------------------------------------------------------
2749 Routines for Field Validation.
2750 --------------------------------------------------------------------------*/
2752 /*---------------------------------------------------------------------------
2753 | Facility : libnform
2754 | Function : static int FV_Validation(FORM * form)
2756 | Description : Validate the current field of the form.
2758 | Return Values : E_OK - field valid
2759 | E_INVALID_FIELD - field not valid
2760 +--------------------------------------------------------------------------*/
2761 static int FV_Validation(FORM * form)
2763 if (_nc_Internal_Validation(form))
2764 return E_OK;
2765 else
2766 return E_INVALID_FIELD;
2768 /*----------------------------------------------------------------------------
2769 End of routines for Field Validation.
2770 --------------------------------------------------------------------------*/
2772 /*----------------------------------------------------------------------------
2773 Helper routines for Inter-Field Navigation
2774 --------------------------------------------------------------------------*/
2776 /*---------------------------------------------------------------------------
2777 | Facility : libnform
2778 | Function : static FIELD *Next_Field_On_Page(FIELD * field)
2780 | Description : Get the next field after the given field on the current
2781 | page. The order of fields is the one defined by the
2782 | fields array. Only visible and active fields are
2783 | counted.
2785 | Return Values : Pointer to the next field.
2786 +--------------------------------------------------------------------------*/
2787 INLINE static FIELD *Next_Field_On_Page(FIELD * field)
2789 FORM *form = field->form;
2790 FIELD **field_on_page = &form->field[field->index];
2791 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2792 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2796 field_on_page =
2797 (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
2798 if (Field_Is_Selectable(*field_on_page))
2799 break;
2800 } while(field!=(*field_on_page));
2801 return(*field_on_page);
2804 /*---------------------------------------------------------------------------
2805 | Facility : libnform
2806 | Function : FIELD* _nc_First_Active_Field(FORM * form)
2808 | Description : Get the first active field on the current page,
2809 | if there are such. If there are none, get the first
2810 | visible field on the page. If there are also none,
2811 | we return the first field on page and hope the best.
2813 | Return Values : Pointer to calculated field.
2814 +--------------------------------------------------------------------------*/
2815 FIELD*
2816 _nc_First_Active_Field(FORM * form)
2818 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2819 FIELD *proposed = Next_Field_On_Page(*last_on_page);
2821 if (proposed == *last_on_page)
2822 { /* there might be the special situation, where there is no
2823 active and visible field on the current page. We then select
2824 the first visible field on this readonly page
2826 if (Field_Is_Not_Selectable(proposed))
2828 FIELD **field = &form->field[proposed->index];
2829 FIELD **first = &form->field[form->page[form->curpage].pmin];
2833 field = (field==last_on_page) ? first : field + 1;
2834 if (((*field)->opts & O_VISIBLE))
2835 break;
2836 } while(proposed!=(*field));
2838 proposed = *field;
2840 if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
2841 { /* This means, there is also no visible field on the page.
2842 So we propose the first one and hope the very best...
2843 Some very clever user has designed a readonly and invisible
2844 page on this form.
2846 proposed = *first;
2850 return(proposed);
2853 /*---------------------------------------------------------------------------
2854 | Facility : libnform
2855 | Function : static FIELD *Previous_Field_On_Page(FIELD * field)
2857 | Description : Get the previous field before the given field on the
2858 | current page. The order of fields is the one defined by
2859 | the fields array. Only visible and active fields are
2860 | counted.
2862 | Return Values : Pointer to the previous field.
2863 +--------------------------------------------------------------------------*/
2864 INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
2866 FORM *form = field->form;
2867 FIELD **field_on_page = &form->field[field->index];
2868 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2869 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2873 field_on_page =
2874 (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
2875 if (Field_Is_Selectable(*field_on_page))
2876 break;
2877 } while(field!=(*field_on_page));
2879 return (*field_on_page);
2882 /*---------------------------------------------------------------------------
2883 | Facility : libnform
2884 | Function : static FIELD *Sorted_Next_Field(FIELD * field)
2886 | Description : Get the next field after the given field on the current
2887 | page. The order of fields is the one defined by the
2888 | (row,column) geometry, rows are major.
2890 | Return Values : Pointer to the next field.
2891 +--------------------------------------------------------------------------*/
2892 INLINE static FIELD *Sorted_Next_Field(FIELD * field)
2894 FIELD *field_on_page = field;
2898 field_on_page = field_on_page->snext;
2899 if (Field_Is_Selectable(field_on_page))
2900 break;
2901 } while(field_on_page!=field);
2903 return (field_on_page);
2906 /*---------------------------------------------------------------------------
2907 | Facility : libnform
2908 | Function : static FIELD *Sorted_Previous_Field(FIELD * field)
2910 | Description : Get the previous field before the given field on the
2911 | current page. The order of fields is the one defined
2912 | by the (row,column) geometry, rows are major.
2914 | Return Values : Pointer to the previous field.
2915 +--------------------------------------------------------------------------*/
2916 INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
2918 FIELD *field_on_page = field;
2922 field_on_page = field_on_page->sprev;
2923 if (Field_Is_Selectable(field_on_page))
2924 break;
2925 } while(field_on_page!=field);
2927 return (field_on_page);
2930 /*---------------------------------------------------------------------------
2931 | Facility : libnform
2932 | Function : static FIELD *Left_Neighbour_Field(FIELD * field)
2934 | Description : Get the left neighbour of the field on the same line
2935 | and the same page. Cycles through the line.
2937 | Return Values : Pointer to left neighbour field.
2938 +--------------------------------------------------------------------------*/
2939 INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
2941 FIELD *field_on_page = field;
2943 /* For a field that has really a left neighbour, the while clause
2944 immediately fails and the loop is left, positioned at the right
2945 neighbour. Otherwise we cycle backwards through the sorted fieldlist
2946 until we enter the same line (from the right end).
2950 field_on_page = Sorted_Previous_Field(field_on_page);
2951 } while(field_on_page->frow != field->frow);
2953 return (field_on_page);
2956 /*---------------------------------------------------------------------------
2957 | Facility : libnform
2958 | Function : static FIELD *Right_Neighbour_Field(FIELD * field)
2960 | Description : Get the right neighbour of the field on the same line
2961 | and the same page.
2963 | Return Values : Pointer to right neighbour field.
2964 +--------------------------------------------------------------------------*/
2965 INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
2967 FIELD *field_on_page = field;
2969 /* See the comments on Left_Neighbour_Field to understand how it works */
2972 field_on_page = Sorted_Next_Field(field_on_page);
2973 } while(field_on_page->frow != field->frow);
2975 return (field_on_page);
2978 /*---------------------------------------------------------------------------
2979 | Facility : libnform
2980 | Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
2982 | Description : Because of the row-major nature of sorting the fields,
2983 | its more difficult to define whats the upper neighbour
2984 | field really means. We define that it must be on a
2985 | 'previous' line (cyclic order!) and is the rightmost
2986 | field laying on the left side of the given field. If
2987 | this set is empty, we take the first field on the line.
2989 | Return Values : Pointer to the upper neighbour field.
2990 +--------------------------------------------------------------------------*/
2991 static FIELD *Upper_Neighbour_Field(FIELD * field)
2993 FIELD *field_on_page = field;
2994 int frow = field->frow;
2995 int fcol = field->fcol;
2997 /* Walk back to the 'previous' line. The second term in the while clause
2998 just guarantees that we stop if we cycled through the line because
2999 there might be no 'previous' line if the page has just one line.
3003 field_on_page = Sorted_Previous_Field(field_on_page);
3004 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3006 if (field_on_page->frow!=frow)
3007 { /* We really found a 'previous' line. We are positioned at the
3008 rightmost field on this line */
3009 frow = field_on_page->frow;
3011 /* We walk to the left as long as we are really right of the
3012 field. */
3013 while(field_on_page->frow==frow && field_on_page->fcol>fcol)
3014 field_on_page = Sorted_Previous_Field(field_on_page);
3016 /* If we wrapped, just go to the right which is the first field on
3017 the row */
3018 if (field_on_page->frow!=frow)
3019 field_on_page = Sorted_Next_Field(field_on_page);
3022 return (field_on_page);
3025 /*---------------------------------------------------------------------------
3026 | Facility : libnform
3027 | Function : static FIELD *Down_Neighbour_Field(FIELD * field)
3029 | Description : Because of the row-major nature of sorting the fields,
3030 | its more difficult to define whats the down neighbour
3031 | field really means. We define that it must be on a
3032 | 'next' line (cyclic order!) and is the leftmost
3033 | field laying on the right side of the given field. If
3034 | this set is empty, we take the last field on the line.
3036 | Return Values : Pointer to the upper neighbour field.
3037 +--------------------------------------------------------------------------*/
3038 static FIELD *Down_Neighbour_Field(FIELD * field)
3040 FIELD *field_on_page = field;
3041 int frow = field->frow;
3042 int fcol = field->fcol;
3044 /* Walk forward to the 'next' line. The second term in the while clause
3045 just guarantees that we stop if we cycled through the line because
3046 there might be no 'next' line if the page has just one line.
3050 field_on_page = Sorted_Next_Field(field_on_page);
3051 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3053 if (field_on_page->frow!=frow)
3054 { /* We really found a 'next' line. We are positioned at the rightmost
3055 field on this line */
3056 frow = field_on_page->frow;
3058 /* We walk to the right as long as we are really left of the
3059 field. */
3060 while(field_on_page->frow==frow && field_on_page->fcol<fcol)
3061 field_on_page = Sorted_Next_Field(field_on_page);
3063 /* If we wrapped, just go to the left which is the last field on
3064 the row */
3065 if (field_on_page->frow!=frow)
3066 field_on_page = Sorted_Previous_Field(field_on_page);
3069 return(field_on_page);
3072 /*----------------------------------------------------------------------------
3073 Inter-Field Navigation routines
3074 --------------------------------------------------------------------------*/
3076 /*---------------------------------------------------------------------------
3077 | Facility : libnform
3078 | Function : static int Inter_Field_Navigation(
3079 | int (* const fct) (FORM *),
3080 | FORM * form)
3082 | Description : Generic behaviour for changing the current field, the
3083 | field is left and a new field is entered. So the field
3084 | must be validated and the field init/term hooks must
3085 | be called.
3087 | Return Values : E_OK - success
3088 | E_INVALID_FIELD - field is invalid
3089 | some other - error from subordinate call
3090 +--------------------------------------------------------------------------*/
3091 static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
3093 int res;
3095 if (!_nc_Internal_Validation(form))
3096 res = E_INVALID_FIELD;
3097 else
3099 Call_Hook(form,fieldterm);
3100 res = fct(form);
3101 Call_Hook(form,fieldinit);
3103 return res;
3106 /*---------------------------------------------------------------------------
3107 | Facility : libnform
3108 | Function : static int FN_Next_Field(FORM * form)
3110 | Description : Move to the next field on the current page of the form
3112 | Return Values : E_OK - success
3113 | != E_OK - error from subordinate call
3114 +--------------------------------------------------------------------------*/
3115 static int FN_Next_Field(FORM * form)
3117 return _nc_Set_Current_Field(form,
3118 Next_Field_On_Page(form->current));
3121 /*---------------------------------------------------------------------------
3122 | Facility : libnform
3123 | Function : static int FN_Previous_Field(FORM * form)
3125 | Description : Move to the previous field on the current page of the
3126 | form
3128 | Return Values : E_OK - success
3129 | != E_OK - error from subordinate call
3130 +--------------------------------------------------------------------------*/
3131 static int FN_Previous_Field(FORM * form)
3133 return _nc_Set_Current_Field(form,
3134 Previous_Field_On_Page(form->current));
3137 /*---------------------------------------------------------------------------
3138 | Facility : libnform
3139 | Function : static int FN_First_Field(FORM * form)
3141 | Description : Move to the first field on the current page of the form
3143 | Return Values : E_OK - success
3144 | != E_OK - error from subordinate call
3145 +--------------------------------------------------------------------------*/
3146 static int FN_First_Field(FORM * form)
3148 return _nc_Set_Current_Field(form,
3149 Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
3152 /*---------------------------------------------------------------------------
3153 | Facility : libnform
3154 | Function : static int FN_Last_Field(FORM * form)
3156 | Description : Move to the last field on the current page of the form
3158 | Return Values : E_OK - success
3159 | != E_OK - error from subordinate call
3160 +--------------------------------------------------------------------------*/
3161 static int FN_Last_Field(FORM * form)
3163 return
3164 _nc_Set_Current_Field(form,
3165 Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
3168 /*---------------------------------------------------------------------------
3169 | Facility : libnform
3170 | Function : static int FN_Sorted_Next_Field(FORM * form)
3172 | Description : Move to the sorted next field on the current page
3173 | of the form.
3175 | Return Values : E_OK - success
3176 | != E_OK - error from subordinate call
3177 +--------------------------------------------------------------------------*/
3178 static int FN_Sorted_Next_Field(FORM * form)
3180 return _nc_Set_Current_Field(form,
3181 Sorted_Next_Field(form->current));
3184 /*---------------------------------------------------------------------------
3185 | Facility : libnform
3186 | Function : static int FN_Sorted_Previous_Field(FORM * form)
3188 | Description : Move to the sorted previous field on the current page
3189 | of the form.
3191 | Return Values : E_OK - success
3192 | != E_OK - error from subordinate call
3193 +--------------------------------------------------------------------------*/
3194 static int FN_Sorted_Previous_Field(FORM * form)
3196 return _nc_Set_Current_Field(form,
3197 Sorted_Previous_Field(form->current));
3200 /*---------------------------------------------------------------------------
3201 | Facility : libnform
3202 | Function : static int FN_Sorted_First_Field(FORM * form)
3204 | Description : Move to the sorted first field on the current page
3205 | of the form.
3207 | Return Values : E_OK - success
3208 | != E_OK - error from subordinate call
3209 +--------------------------------------------------------------------------*/
3210 static int FN_Sorted_First_Field(FORM * form)
3212 return _nc_Set_Current_Field(form,
3213 Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
3216 /*---------------------------------------------------------------------------
3217 | Facility : libnform
3218 | Function : static int FN_Sorted_Last_Field(FORM * form)
3220 | Description : Move to the sorted last field on the current page
3221 | of the form.
3223 | Return Values : E_OK - success
3224 | != E_OK - error from subordinate call
3225 +--------------------------------------------------------------------------*/
3226 static int FN_Sorted_Last_Field(FORM * form)
3228 return _nc_Set_Current_Field(form,
3229 Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
3232 /*---------------------------------------------------------------------------
3233 | Facility : libnform
3234 | Function : static int FN_Left_Field(FORM * form)
3236 | Description : Get the field on the left of the current field on the
3237 | same line and the same page. Cycles through the line.
3239 | Return Values : E_OK - success
3240 | != E_OK - error from subordinate call
3241 +--------------------------------------------------------------------------*/
3242 static int FN_Left_Field(FORM * form)
3244 return _nc_Set_Current_Field(form,
3245 Left_Neighbour_Field(form->current));
3248 /*---------------------------------------------------------------------------
3249 | Facility : libnform
3250 | Function : static int FN_Right_Field(FORM * form)
3252 | Description : Get the field on the right of the current field on the
3253 | same line and the same page. Cycles through the line.
3255 | Return Values : E_OK - success
3256 | != E_OK - error from subordinate call
3257 +--------------------------------------------------------------------------*/
3258 static int FN_Right_Field(FORM * form)
3260 return _nc_Set_Current_Field(form,
3261 Right_Neighbour_Field(form->current));
3264 /*---------------------------------------------------------------------------
3265 | Facility : libnform
3266 | Function : static int FN_Up_Field(FORM * form)
3268 | Description : Get the upper neighbour of the current field. This
3269 | cycles through the page. See the comments of the
3270 | Upper_Neighbour_Field function to understand how
3271 | 'upper' is defined.
3273 | Return Values : E_OK - success
3274 | != E_OK - error from subordinate call
3275 +--------------------------------------------------------------------------*/
3276 static int FN_Up_Field(FORM * form)
3278 return _nc_Set_Current_Field(form,
3279 Upper_Neighbour_Field(form->current));
3282 /*---------------------------------------------------------------------------
3283 | Facility : libnform
3284 | Function : static int FN_Down_Field(FORM * form)
3286 | Description : Get the down neighbour of the current field. This
3287 | cycles through the page. See the comments of the
3288 | Down_Neighbour_Field function to understand how
3289 | 'down' is defined.
3291 | Return Values : E_OK - success
3292 | != E_OK - error from subordinate call
3293 +--------------------------------------------------------------------------*/
3294 static int FN_Down_Field(FORM * form)
3296 return _nc_Set_Current_Field(form,
3297 Down_Neighbour_Field(form->current));
3299 /*----------------------------------------------------------------------------
3300 END of Field Navigation routines
3301 --------------------------------------------------------------------------*/
3303 /*----------------------------------------------------------------------------
3304 Helper routines for Page Navigation
3305 --------------------------------------------------------------------------*/
3307 /*---------------------------------------------------------------------------
3308 | Facility : libnform
3309 | Function : int _nc_Set_Form_Page(FORM * form,
3310 | int page,
3311 | FIELD * field)
3313 | Description : Make the given page nr. the current page and make
3314 | the given field the current field on the page. If
3315 | for the field NULL is given, make the first field on
3316 | the page the current field. The routine acts only
3317 | if the requested page is not the current page.
3319 | Return Values : E_OK - success
3320 | != E_OK - error from subordinate call
3321 +--------------------------------------------------------------------------*/
3323 _nc_Set_Form_Page(FORM * form, int page, FIELD * field)
3325 int res = E_OK;
3327 if ((form->curpage!=page))
3329 FIELD *last_field, *field_on_page;
3331 werase(Get_Form_Window(form));
3332 form->curpage = page;
3333 last_field = field_on_page = form->field[form->page[page].smin];
3336 if (field_on_page->opts & O_VISIBLE)
3337 if ((res=Display_Field(field_on_page))!=E_OK)
3338 return(res);
3339 field_on_page = field_on_page->snext;
3340 } while(field_on_page != last_field);
3342 if (field)
3343 res = _nc_Set_Current_Field(form,field);
3344 else
3345 /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
3346 because this is already executed in a page navigation
3347 context that contains field navigation
3349 res = FN_First_Field(form);
3351 return(res);
3354 /*---------------------------------------------------------------------------
3355 | Facility : libnform
3356 | Function : static int Next_Page_Number(const FORM * form)
3358 | Description : Calculate the page number following the current page
3359 | number. This cycles if the highest page number is
3360 | reached.
3362 | Return Values : The next page number
3363 +--------------------------------------------------------------------------*/
3364 INLINE static int Next_Page_Number(const FORM * form)
3366 return (form->curpage + 1) % form->maxpage;
3369 /*---------------------------------------------------------------------------
3370 | Facility : libnform
3371 | Function : static int Previous_Page_Number(const FORM * form)
3373 | Description : Calculate the page number before the current page
3374 | number. This cycles if the first page number is
3375 | reached.
3377 | Return Values : The previous page number
3378 +--------------------------------------------------------------------------*/
3379 INLINE static int Previous_Page_Number(const FORM * form)
3381 return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
3384 /*----------------------------------------------------------------------------
3385 Page Navigation routines
3386 --------------------------------------------------------------------------*/
3388 /*---------------------------------------------------------------------------
3389 | Facility : libnform
3390 | Function : static int Page_Navigation(
3391 | int (* const fct) (FORM *),
3392 | FORM * form)
3394 | Description : Generic behaviour for changing a page. This means
3395 | that the field is left and a new field is entered.
3396 | So the field must be validated and the field init/term
3397 | hooks must be called. Because also the page is changed,
3398 | the forms init/term hooks must be called also.
3400 | Return Values : E_OK - success
3401 | E_INVALID_FIELD - field is invalid
3402 | some other - error from subordinate call
3403 +--------------------------------------------------------------------------*/
3404 static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
3406 int res;
3408 if (!_nc_Internal_Validation(form))
3409 res = E_INVALID_FIELD;
3410 else
3412 Call_Hook(form,fieldterm);
3413 Call_Hook(form,formterm);
3414 res = fct(form);
3415 Call_Hook(form,forminit);
3416 Call_Hook(form,fieldinit);
3418 return res;
3421 /*---------------------------------------------------------------------------
3422 | Facility : libnform
3423 | Function : static int PN_Next_Page(FORM * form)
3425 | Description : Move to the next page of the form
3427 | Return Values : E_OK - success
3428 | != E_OK - error from subordinate call
3429 +--------------------------------------------------------------------------*/
3430 static int PN_Next_Page(FORM * form)
3432 return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
3435 /*---------------------------------------------------------------------------
3436 | Facility : libnform
3437 | Function : static int PN_Previous_Page(FORM * form)
3439 | Description : Move to the previous page of the form
3441 | Return Values : E_OK - success
3442 | != E_OK - error from subordinate call
3443 +--------------------------------------------------------------------------*/
3444 static int PN_Previous_Page(FORM * form)
3446 return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
3449 /*---------------------------------------------------------------------------
3450 | Facility : libnform
3451 | Function : static int PN_First_Page(FORM * form)
3453 | Description : Move to the first page of the form
3455 | Return Values : E_OK - success
3456 | != E_OK - error from subordinate call
3457 +--------------------------------------------------------------------------*/
3458 static int PN_First_Page(FORM * form)
3460 return _nc_Set_Form_Page(form,0,(FIELD *)0);
3463 /*---------------------------------------------------------------------------
3464 | Facility : libnform
3465 | Function : static int PN_Last_Page(FORM * form)
3467 | Description : Move to the last page of the form
3469 | Return Values : E_OK - success
3470 | != E_OK - error from subordinate call
3471 +--------------------------------------------------------------------------*/
3472 static int PN_Last_Page(FORM * form)
3474 return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
3476 /*----------------------------------------------------------------------------
3477 END of Field Navigation routines
3478 --------------------------------------------------------------------------*/
3480 /*----------------------------------------------------------------------------
3481 Helper routines for the core form driver.
3482 --------------------------------------------------------------------------*/
3484 /*---------------------------------------------------------------------------
3485 | Facility : libnform
3486 | Function : static int Data_Entry(FORM * form,int c)
3488 | Description : Enter character c into at the current position of the
3489 | current field of the form.
3491 | Return Values : E_OK -
3492 | E_REQUEST_DENIED -
3493 | E_SYSTEM_ERROR -
3494 +--------------------------------------------------------------------------*/
3495 static int Data_Entry(FORM * form, int c)
3497 FIELD *field = form->current;
3498 int result = E_REQUEST_DENIED;
3500 if ( (field->opts & O_EDIT)
3501 #if FIX_FORM_INACTIVE_BUG
3502 && (field->opts & O_ACTIVE)
3503 #endif
3506 if ( (field->opts & O_BLANK) &&
3507 First_Position_In_Current_Field(form) &&
3508 !(form->status & _FCHECK_REQUIRED) &&
3509 !(form->status & _WINDOW_MODIFIED) )
3510 werase(form->w);
3512 if (form->status & _OVLMODE)
3514 waddch(form->w,(chtype)c);
3516 else /* no _OVLMODE */
3518 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
3520 if (!(There_Is_Room ||
3521 ((Single_Line_Field(field) && Growable(field)))))
3522 return E_REQUEST_DENIED;
3524 if (!There_Is_Room && !Field_Grown(field,1))
3525 return E_SYSTEM_ERROR;
3527 winsch(form->w,(chtype)c);
3530 if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
3532 bool End_Of_Field= (((field->drows-1)==form->currow) &&
3533 ((field->dcols-1)==form->curcol));
3534 form->status |= _WINDOW_MODIFIED;
3535 if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3536 result = Inter_Field_Navigation(FN_Next_Field,form);
3537 else
3539 if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
3540 result = E_SYSTEM_ERROR;
3541 else
3543 IFN_Next_Character(form);
3544 result = E_OK;
3549 return result;
3552 /* Structure to describe the binding of a request code to a function.
3553 The member keycode codes the request value as well as the generic
3554 routine to use for the request. The code for the generic routine
3555 is coded in the upper 16 Bits while the request code is coded in
3556 the lower 16 bits.
3558 In terms of C++ you might think of a request as a class with a
3559 virtual method "perform". The different types of request are
3560 derived from this base class and overload (or not) the base class
3561 implementation of perform.
3563 typedef struct {
3564 int keycode; /* must be at least 32 bit: hi:mode, lo: key */
3565 int (*cmd)(FORM *); /* low level driver routine for this key */
3566 } Binding_Info;
3568 /* You may see this is the class-id of the request type class */
3569 #define ID_PN (0x00000000) /* Page navigation */
3570 #define ID_FN (0x00010000) /* Inter-Field navigation */
3571 #define ID_IFN (0x00020000) /* Intra-Field navigation */
3572 #define ID_VSC (0x00030000) /* Vertical Scrolling */
3573 #define ID_HSC (0x00040000) /* Horizontal Scrolling */
3574 #define ID_FE (0x00050000) /* Field Editing */
3575 #define ID_EM (0x00060000) /* Edit Mode */
3576 #define ID_FV (0x00070000) /* Field Validation */
3577 #define ID_CH (0x00080000) /* Choice */
3578 #define ID_Mask (0xffff0000)
3579 #define Key_Mask (0x0000ffff)
3580 #define ID_Shft (16)
3582 /* This array holds all the Binding Infos */
3583 static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
3585 { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
3586 { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
3587 { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
3588 { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
3590 { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
3591 { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
3592 { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
3593 { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
3594 { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
3595 { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
3596 { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
3597 { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
3598 { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
3599 { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
3600 { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
3601 { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
3603 { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
3604 { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
3605 { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
3606 { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
3607 { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
3608 { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
3609 { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
3610 { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
3611 { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
3612 { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
3613 { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
3614 { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
3615 { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
3616 { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
3618 { REQ_NEW_LINE |ID_FE ,FE_New_Line},
3619 { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
3620 { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
3621 { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
3622 { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
3623 { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
3624 { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
3625 { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
3626 { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
3627 { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
3629 { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
3630 { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
3632 { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
3633 { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
3634 { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
3635 { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
3636 { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
3637 { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
3639 { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
3640 { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
3641 { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
3642 { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
3643 { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
3644 { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
3646 { REQ_VALIDATION |ID_FV ,FV_Validation},
3648 { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
3649 { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
3652 /*---------------------------------------------------------------------------
3653 | Facility : libnform
3654 | Function : int form_driver(FORM * form,int c)
3656 | Description : This is the workhorse of the forms system. It checks
3657 | to determine whether the character c is a request or
3658 | data. If it is a request, the form driver executes
3659 | the request and returns the result. If it is data
3660 | (printable character), it enters the data into the
3661 | current position in the current field. If it is not
3662 | recognized, the form driver assumes it is an application
3663 | defined command and returns E_UNKNOWN_COMMAND.
3664 | Application defined command should be defined relative
3665 | to MAX_FORM_COMMAND, the maximum value of a request.
3667 | Return Values : E_OK - success
3668 | E_SYSTEM_ERROR - system error
3669 | E_BAD_ARGUMENT - an argument is incorrect
3670 | E_NOT_POSTED - form is not posted
3671 | E_INVALID_FIELD - field contents are invalid
3672 | E_BAD_STATE - called from inside a hook routine
3673 | E_REQUEST_DENIED - request failed
3674 | E_UNKNOWN_COMMAND - command not known
3675 +--------------------------------------------------------------------------*/
3676 int form_driver(FORM * form, int c)
3678 const Binding_Info* BI = (Binding_Info *)0;
3679 int res = E_UNKNOWN_COMMAND;
3681 if (!form)
3682 RETURN(E_BAD_ARGUMENT);
3684 if (!(form->field))
3685 RETURN(E_NOT_CONNECTED);
3687 assert(form->page != 0);
3689 if (c==FIRST_ACTIVE_MAGIC)
3691 form->current = _nc_First_Active_Field(form);
3692 return E_OK;
3695 assert(form->current &&
3696 form->current->buf &&
3697 (form->current->form == form)
3700 if ( form->status & _IN_DRIVER )
3701 RETURN(E_BAD_STATE);
3703 if ( !( form->status & _POSTED ) )
3704 RETURN(E_NOT_POSTED);
3706 if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
3707 ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
3708 BI = &(bindings[c-MIN_FORM_COMMAND]);
3710 if (BI)
3712 typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
3713 static const Generic_Method Generic_Methods[] =
3715 Page_Navigation, /* overloaded to call field&form hooks */
3716 Inter_Field_Navigation, /* overloaded to call field hooks */
3717 NULL, /* Intra-Field is generic */
3718 Vertical_Scrolling, /* Overloaded to check multi-line */
3719 Horizontal_Scrolling, /* Overloaded to check single-line */
3720 Field_Editing, /* Overloaded to mark modification */
3721 NULL, /* Edit Mode is generic */
3722 NULL, /* Field Validation is generic */
3723 NULL /* Choice Request is generic */
3725 size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
3726 size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
3728 if ( (method >= nMethods) || !(BI->cmd) )
3729 res = E_SYSTEM_ERROR;
3730 else
3732 Generic_Method fct = Generic_Methods[method];
3733 if (fct)
3734 res = fct(BI->cmd,form);
3735 else
3736 res = (BI->cmd)(form);
3739 else
3741 if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
3742 isprint((unsigned char)c) &&
3743 Check_Char(form->current->type,c,
3744 (TypeArgument *)(form->current->arg)))
3745 res = Data_Entry(form,c);
3747 _nc_Refresh_Current_Field(form);
3748 RETURN(res);
3751 /*----------------------------------------------------------------------------
3752 Field-Buffer manipulation routines.
3753 The effects of setting a buffer is tightly coupled to the core of the form
3754 driver logic. This is especially true in the case of growable fields.
3755 So I don't separate this into an own module.
3756 --------------------------------------------------------------------------*/
3758 /*---------------------------------------------------------------------------
3759 | Facility : libnform
3760 | Function : int set_field_buffer(FIELD *field,
3761 | int buffer, char *value)
3763 | Description : Set the given buffer of the field to the given value.
3764 | Buffer 0 stores the displayed content of the field.
3765 | For dynamic fields this may grow the fieldbuffers if
3766 | the length of the value exceeds the current buffer
3767 | length. For buffer 0 only printable values are allowed.
3768 | For static fields, the value needs not to be zero ter-
3769 | minated. It is copied up to the length of the buffer.
3771 | Return Values : E_OK - success
3772 | E_BAD_ARGUMENT - invalid argument
3773 | E_SYSTEM_ERROR - system error
3774 +--------------------------------------------------------------------------*/
3775 int set_field_buffer(FIELD * field, int buffer, const char * value)
3777 char *s, *p;
3778 int res = E_OK;
3779 unsigned int len;
3781 if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
3782 RETURN(E_BAD_ARGUMENT);
3784 len = Buffer_Length(field);
3786 if (buffer==0)
3788 const char *v;
3789 unsigned int i = 0;
3791 for(v=value; *v && (i<len); v++,i++)
3793 if (!isprint((unsigned char)*v))
3794 RETURN(E_BAD_ARGUMENT);
3798 if (Growable(field))
3800 /* for a growable field we must assume zero terminated strings, because
3801 somehow we have to detect the length of what should be copied.
3803 unsigned int vlen = strlen(value);
3804 if (vlen > len)
3806 if (!Field_Grown(field,
3807 (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
3808 RETURN(E_SYSTEM_ERROR);
3810 /* in this case we also have to check, wether or not the remaining
3811 characters in value are also printable for buffer 0. */
3812 if (buffer==0)
3814 unsigned int i;
3816 for(i=len; i<vlen; i++)
3817 if (!isprint((int)(value[i])))
3818 RETURN(E_BAD_ARGUMENT);
3820 len = vlen;
3824 p = Address_Of_Nth_Buffer(field,buffer);
3826 #if HAVE_MEMCCPY
3827 s = memccpy(p,value,0,len);
3828 #else
3829 for(s=(char *)value; *s && (s < (value+len)); s++)
3830 p[s-value] = *s;
3831 if (s < (value+len))
3833 int off = s-value;
3834 p[off] = *s++;
3835 s = p + (s-value);
3837 else
3838 s=(char *)0;
3839 #endif
3841 if (s)
3842 { /* this means, value was null terminated and not greater than the
3843 buffer. We have to pad with blanks. Please note that due to memccpy
3844 logic s points after the terminating null. */
3845 s--; /* now we point to the terminator. */
3846 assert(len >= (unsigned int)(s-p));
3847 if (len > (unsigned int)(s-p))
3848 memset(s,C_BLANK,len-(unsigned int)(s-p));
3851 if (buffer==0)
3853 int syncres;
3854 if (((syncres=Synchronize_Field( field ))!=E_OK) &&
3855 (res==E_OK))
3856 res = syncres;
3857 if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
3858 (res==E_OK))
3859 res = syncres;
3861 RETURN(res);
3864 /*---------------------------------------------------------------------------
3865 | Facility : libnform
3866 | Function : char *field_buffer(const FIELD *field,int buffer)
3868 | Description : Return the address of the buffer for the field.
3870 | Return Values : Pointer to buffer or NULL if arguments were invalid.
3871 +--------------------------------------------------------------------------*/
3872 char *field_buffer(const FIELD * field, int buffer)
3874 if (field && (buffer >= 0) && (buffer <= field->nbuf))
3875 return Address_Of_Nth_Buffer(field,buffer);
3876 else
3877 return (char *)0;
3880 /* frm_driver.c ends here */