Start sentences on a new line, fix typo and use .An.
[dragonfly.git] / contrib / ncurses-5.4 / form / frm_driver.c
blob9de28eeabbd3aa8770d2bbfc6a9aa137cad8d35f
1 /****************************************************************************
2 * Copyright (c) 1998-2002,2003 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, 1995,1997 *
31 ****************************************************************************/
33 #include "form.priv.h"
35 MODULE_ID("$Id: frm_driver.c,v 1.45 2003/12/06 17:22:42 tom Exp $")
37 /*----------------------------------------------------------------------------
38 This is the core module of the form library. It contains the majority
39 of the driver routines as well as the form_driver function.
41 Essentially this module is nearly the whole library. This is because
42 all the functions in this module depends on some others in the module,
43 so it makes no sense to split them into separate files because they
44 will always be linked together. The only acceptable concern is turnaround
45 time for this module, but now we have all Pentiums or RISCs, so what!
47 The driver routines are grouped into nine generic categories:
49 a) Page Navigation ( all functions prefixed by PN_ )
50 The current page of the form is left and some new page is
51 entered.
52 b) Inter-Field Navigation ( all functions prefixed by FN_ )
53 The current field of the form is left and some new field is
54 entered.
55 c) Intra-Field Navigation ( all functions prefixed by IFN_ )
56 The current position in the current field is changed.
57 d) Vertical Scrolling ( all functions prefixed by VSC_ )
58 Essentially this is a specialization of Intra-Field navigation.
59 It has to check for a multi-line field.
60 e) Horizontal Scrolling ( all functions prefixed by HSC_ )
61 Essentially this is a specialization of Intra-Field navigation.
62 It has to check for a single-line field.
63 f) Field Editing ( all functions prefixed by FE_ )
64 The content of the current field is changed
65 g) Edit Mode requests ( all functions prefixed by EM_ )
66 Switching between insert and overlay mode
67 h) Field-Validation requests ( all functions prefixed by FV_ )
68 Perform verifications of the field.
69 i) Choice requests ( all functions prefixed by CR_ )
70 Requests to enumerate possible field values
71 --------------------------------------------------------------------------*/
73 /*----------------------------------------------------------------------------
74 Some remarks on the placements of assert() macros :
75 I use them only on "strategic" places, i.e. top level entries where
76 I want to make sure that things are set correctly. Throughout subordinate
77 routines I omit them mostly.
78 --------------------------------------------------------------------------*/
81 Some options that may effect compatibility in behavior to SVr4 forms,
82 but they are here to allow a more intuitive and user friendly behavior of
83 our form implementation. This doesn't affect the API, so we feel it is
84 uncritical.
86 The initial implementation tries to stay very close with the behavior
87 of the original SVr4 implementation, although in some areas it is quite
88 clear that this isn't the most appropriate way. As far as possible this
89 sources will allow you to build a forms lib that behaves quite similar
90 to SVr4, but now and in the future we will give you better options.
91 Perhaps at some time we will make this configurable at runtime.
94 /* Implement a more user-friendly previous/next word behavior */
95 #define FRIENDLY_PREV_NEXT_WORD (1)
96 /* Fix the wrong behavior for forms with all fields inactive */
97 #define FIX_FORM_INACTIVE_BUG (1)
98 /* Allow dynamic field growth also when navigating past the end */
99 #define GROW_IF_NAVIGATE (1)
101 /*----------------------------------------------------------------------------
102 Forward references to some internally used static functions
103 --------------------------------------------------------------------------*/
104 static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
105 static int FN_Next_Field (FORM * form);
106 static int FN_Previous_Field (FORM * form);
107 static int FE_New_Line(FORM *);
108 static int FE_Delete_Previous(FORM *);
110 /*----------------------------------------------------------------------------
111 Macro Definitions.
113 Some Remarks on that: I use the convention to use UPPERCASE for constants
114 defined by Macros. If I provide a macro as a kind of inline routine to
115 provide some logic, I use my Upper_Lower case style.
116 --------------------------------------------------------------------------*/
118 /* Calculate the position of a single row in a field buffer */
119 #define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
121 /* Calculate start address for the fields buffer# N */
122 #define Address_Of_Nth_Buffer(field,N) \
123 ((field)->buf + (N)*(1+Buffer_Length(field)))
125 /* Calculate the start address of the row in the fields specified buffer# N */
126 #define Address_Of_Row_In_Nth_Buffer(field,N,row) \
127 (Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
129 /* Calculate the start address of the row in the fields primary buffer */
130 #define Address_Of_Row_In_Buffer(field,row) \
131 Address_Of_Row_In_Nth_Buffer(field,0,row)
133 /* Calculate the start address of the row in the forms current field
134 buffer# N */
135 #define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
136 Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
138 /* Calculate the start address of the row in the forms current field
139 primary buffer */
140 #define Address_Of_Current_Row_In_Buffer(form) \
141 Address_Of_Current_Row_In_Nth_Buffer(form,0)
143 /* Calculate the address of the cursor in the forms current field
144 primary buffer */
145 #define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
146 (Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
148 /* Calculate the address of the cursor in the forms current field
149 buffer# N */
150 #define Address_Of_Current_Position_In_Buffer(form) \
151 Address_Of_Current_Position_In_Nth_Buffer(form,0)
153 /* Logic to decide whether or not a field is actually a field with
154 vertical or horizontal scrolling */
155 #define Is_Scroll_Field(field) \
156 (((field)->drows > (field)->rows) || \
157 ((field)->dcols > (field)->cols))
159 /* Logic to decide whether or not a field needs to have an individual window
160 instead of a derived window because it contains invisible parts.
161 This is true for non-public fields and for scrollable fields. */
162 #define Has_Invisible_Parts(field) \
163 (!((field)->opts & O_PUBLIC) || \
164 Is_Scroll_Field(field))
166 /* Logic to decide whether or not a field needs justification */
167 #define Justification_Allowed(field) \
168 (((field)->just != NO_JUSTIFICATION) && \
169 (Single_Line_Field(field)) && \
170 (((field)->dcols == (field)->cols) && \
171 ((field)->opts & O_STATIC)) )
173 /* Logic to determine whether or not a dynamic field may still grow */
174 #define Growable(field) ((field)->status & _MAY_GROW)
176 /* Macro to set the attributes for a fields window */
177 #define Set_Field_Window_Attributes(field,win) \
178 ( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
179 wattrset((win),(field)->fore) )
181 /* Logic to decide whether or not a field really appears on the form */
182 #define Field_Really_Appears(field) \
183 ((field->form) &&\
184 (field->form->status & _POSTED) &&\
185 (field->opts & O_VISIBLE) &&\
186 (field->page == field->form->curpage))
188 /* Logic to determine whether or not we are on the first position in the
189 current field */
190 #define First_Position_In_Current_Field(form) \
191 (((form)->currow==0) && ((form)->curcol==0))
194 #define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
195 #define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
197 /*---------------------------------------------------------------------------
198 | Facility : libnform
199 | Function : static char *Get_Start_Of_Data(char * buf, int blen)
201 | Description : Return pointer to first non-blank position in buffer.
202 | If buffer is empty return pointer to buffer itself.
204 | Return Values : Pointer to first non-blank position in buffer
205 +--------------------------------------------------------------------------*/
206 INLINE static char *Get_Start_Of_Data(char * buf, int blen)
208 char *p = buf;
209 char *end = &buf[blen];
211 assert(buf && blen>=0);
212 while( (p < end) && is_blank(*p) )
213 p++;
214 return( (p==end) ? buf : p );
217 /*---------------------------------------------------------------------------
218 | Facility : libnform
219 | Function : static char *After_End_Of_Data(char * buf, int blen)
221 | Description : Return pointer after last non-blank position in buffer.
222 | If buffer is empty, return pointer to buffer itself.
224 | Return Values : Pointer to position after last non-blank position in
225 | buffer.
226 +--------------------------------------------------------------------------*/
227 INLINE static char *After_End_Of_Data(char * buf,int blen)
229 char *p = &buf[blen];
231 assert(buf && blen>=0);
232 while( (p>buf) && is_blank(p[-1]) )
233 p--;
234 return( p );
237 /*---------------------------------------------------------------------------
238 | Facility : libnform
239 | Function : static char *Get_First_Whitespace_Character(
240 | char * buf, int blen)
242 | Description : Position to the first whitespace character.
244 | Return Values : Pointer to first whitespace character in buffer.
245 +--------------------------------------------------------------------------*/
246 INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
248 char *p = buf;
249 char *end = &p[blen];
251 assert(buf && blen>=0);
252 while( (p < end) && !is_blank(*p))
253 p++;
254 return( (p==end) ? buf : p );
257 /*---------------------------------------------------------------------------
258 | Facility : libnform
259 | Function : static char *After_Last_Whitespace_Character(
260 | char * buf, int blen)
262 | Description : Get the position after the last whitespace character.
264 | Return Values : Pointer to position after last whitespace character in
265 | buffer.
266 +--------------------------------------------------------------------------*/
267 INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
269 char *p = &buf[blen];
271 assert(buf && blen>=0);
272 while( (p>buf) && !is_blank(p[-1]) )
273 p--;
274 return( p );
277 /* Set this to 1 to use the div_t version. This is a good idea if your
278 compiler has an intrinsic div() support. Unfortunately GNU-C has it
279 not yet.
280 N.B.: This only works if form->curcol follows immediately form->currow
281 and both are of type int.
283 #define USE_DIV_T (0)
285 /*---------------------------------------------------------------------------
286 | Facility : libnform
287 | Function : static void Adjust_Cursor_Position(
288 | FORM * form, const char * pos)
290 | Description : Set current row and column of the form to values
291 | corresponding to the buffer position.
293 | Return Values : -
294 +--------------------------------------------------------------------------*/
295 INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
297 FIELD *field;
298 int idx;
300 field = form->current;
301 assert( pos >= field->buf && field->dcols > 0);
302 idx = (int)( pos - field->buf );
303 #if USE_DIV_T
304 *((div_t *)&(form->currow)) = div(idx,field->dcols);
305 #else
306 form->currow = idx / field->dcols;
307 form->curcol = idx - field->cols * form->currow;
308 #endif
309 if ( field->drows < form->currow )
310 form->currow = 0;
313 /*---------------------------------------------------------------------------
314 | Facility : libnform
315 | Function : static void Buffer_To_Window(
316 | const FIELD * field,
317 | WINDOW * win)
319 | Description : Copy the buffer to the window. If it is a multi-line
320 | field, the buffer is split to the lines of the
321 | window without any editing.
323 | Return Values : -
324 +--------------------------------------------------------------------------*/
325 static void Buffer_To_Window(const FIELD * field, WINDOW * win)
327 int width, height;
328 int len;
329 int row;
330 char *pBuffer;
332 assert(win && field);
334 width = getmaxx(win);
335 height = getmaxy(win);
337 for(row=0, pBuffer=field->buf;
338 row < height;
339 row++, pBuffer += width )
341 if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
343 wmove( win, row, 0 );
344 waddnstr( win, pBuffer, len );
349 /*---------------------------------------------------------------------------
350 | Facility : libnform
351 | Function : static void Window_To_Buffer(
352 | WINDOW * win,
353 | FIELD * field)
355 | Description : Copy the content of the window into the buffer.
356 | The multiple lines of a window are simply
357 | concatenated into the buffer. Pad characters in
358 | the window will be replaced by blanks in the buffer.
360 | Return Values : -
361 +--------------------------------------------------------------------------*/
362 static void Window_To_Buffer(WINDOW * win, FIELD * field)
364 int pad;
365 int len = 0;
366 char *p;
367 int row, height;
369 assert(win && field && field->buf );
371 pad = field->pad;
372 p = field->buf;
373 height = getmaxy(win);
375 for(row=0; (row < height) && (row < field->drows); row++ )
377 wmove( win, row, 0 );
378 len += winnstr( win, p+len, field->dcols );
380 p[len] = '\0';
382 /* replace visual padding character by blanks in buffer */
383 if (pad != C_BLANK)
385 int i;
386 for(i=0; i<len; i++, p++)
388 if (*p==pad)
389 *p = C_BLANK;
394 /*---------------------------------------------------------------------------
395 | Facility : libnform
396 | Function : static void Synchronize_Buffer(FORM * form)
398 | Description : If there was a change, copy the content of the
399 | window into the buffer, so the buffer is synchronized
400 | with the windows content. We have to indicate that the
401 | buffer needs validation due to the change.
403 | Return Values : -
404 +--------------------------------------------------------------------------*/
405 INLINE static void Synchronize_Buffer(FORM * form)
407 if (form->status & _WINDOW_MODIFIED)
409 form->status &= ~_WINDOW_MODIFIED;
410 form->status |= _FCHECK_REQUIRED;
411 Window_To_Buffer(form->w,form->current);
412 wmove(form->w,form->currow,form->curcol);
416 /*---------------------------------------------------------------------------
417 | Facility : libnform
418 | Function : static bool Field_Grown( FIELD *field, int amount)
420 | Description : This function is called for growable dynamic fields
421 | only. It has to increase the buffers and to allocate
422 | a new window for this field.
423 | This function has the side effect to set a new
424 | field-buffer pointer, the dcols and drows values
425 | as well as a new current Window for the field.
427 | Return Values : TRUE - field successfully increased
428 | FALSE - there was some error
429 +--------------------------------------------------------------------------*/
430 static bool Field_Grown(FIELD * field, int amount)
432 bool result = FALSE;
434 if (field && Growable(field))
436 bool single_line_field = Single_Line_Field(field);
437 int old_buflen = Buffer_Length(field);
438 int new_buflen;
439 int old_dcols = field->dcols;
440 int old_drows = field->drows;
441 char *oldbuf = field->buf;
442 char *newbuf;
444 int growth;
445 FORM *form = field->form;
446 bool need_visual_update = ((form != (FORM *)0) &&
447 (form->status & _POSTED) &&
448 (form->current==field));
450 if (need_visual_update)
451 Synchronize_Buffer(form);
453 if (single_line_field)
455 growth = field->cols * amount;
456 if (field->maxgrow)
457 growth = Minimum(field->maxgrow - field->dcols,growth);
458 field->dcols += growth;
459 if (field->dcols == field->maxgrow)
460 field->status &= ~_MAY_GROW;
462 else
464 growth = (field->rows + field->nrow) * amount;
465 if (field->maxgrow)
466 growth = Minimum(field->maxgrow - field->drows,growth);
467 field->drows += growth;
468 if (field->drows == field->maxgrow)
469 field->status &= ~_MAY_GROW;
471 /* drows, dcols changed, so we get really the new buffer length */
472 new_buflen = Buffer_Length(field);
473 newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
474 if (!newbuf)
475 { /* restore to previous state */
476 field->dcols = old_dcols;
477 field->drows = old_drows;
478 if (( single_line_field && (field->dcols!=field->maxgrow)) ||
479 (!single_line_field && (field->drows!=field->maxgrow)))
480 field->status |= _MAY_GROW;
481 return FALSE;
483 else
484 { /* Copy all the buffers. This is the reason why we can't
485 just use realloc().
487 int i;
488 char *old_bp;
489 char *new_bp;
491 field->buf = newbuf;
492 for(i=0;i<=field->nbuf;i++)
494 new_bp = Address_Of_Nth_Buffer(field,i);
495 old_bp = oldbuf + i*(1+old_buflen);
496 memcpy(new_bp,old_bp,(size_t)old_buflen);
497 if (new_buflen > old_buflen)
498 memset(new_bp + old_buflen,C_BLANK,
499 (size_t)(new_buflen - old_buflen));
500 *(new_bp + new_buflen) = '\0';
503 if (need_visual_update)
505 WINDOW *new_window = newpad(field->drows,field->dcols);
506 if (!new_window)
507 { /* restore old state */
508 field->dcols = old_dcols;
509 field->drows = old_drows;
510 field->buf = oldbuf;
511 if (( single_line_field &&
512 (field->dcols!=field->maxgrow)) ||
513 (!single_line_field &&
514 (field->drows!=field->maxgrow)))
515 field->status |= _MAY_GROW;
516 free( newbuf );
517 return FALSE;
519 assert(form!=(FORM *)0);
520 if (form->w)
521 delwin(form->w);
522 form->w = new_window;
523 Set_Field_Window_Attributes(field,form->w);
524 werase(form->w);
525 Buffer_To_Window(field,form->w);
526 untouchwin(form->w);
527 wmove(form->w,form->currow,form->curcol);
530 free(oldbuf);
531 /* reflect changes in linked fields */
532 if (field != field->link)
534 FIELD *linked_field;
535 for(linked_field = field->link;
536 linked_field!= field;
537 linked_field = linked_field->link)
539 linked_field->buf = field->buf;
540 linked_field->drows = field->drows;
541 linked_field->dcols = field->dcols;
544 result = TRUE;
547 return(result);
550 /*---------------------------------------------------------------------------
551 | Facility : libnform
552 | Function : int _nc_Position_Form_Cursor(FORM * form)
554 | Description : Position the cursor in the window for the current
555 | field to be in sync. with the currow and curcol
556 | values.
558 | Return Values : E_OK - success
559 | E_BAD_ARGUMENT - invalid form pointer
560 | E_SYSTEM_ERROR - form has no current field or
561 | field-window
562 +--------------------------------------------------------------------------*/
563 NCURSES_EXPORT(int)
564 _nc_Position_Form_Cursor (FORM * form)
566 FIELD *field;
567 WINDOW *formwin;
569 if (!form)
570 return(E_BAD_ARGUMENT);
572 if (!form->w || !form->current)
573 return(E_SYSTEM_ERROR);
575 field = form->current;
576 formwin = Get_Form_Window(form);
578 wmove( form->w, form->currow, form->curcol );
579 if ( Has_Invisible_Parts(field) )
581 /* in this case fieldwin isn't derived from formwin, so we have
582 to move the cursor in formwin by hand... */
583 wmove(formwin,
584 field->frow + form->currow - form->toprow,
585 field->fcol + form->curcol - form->begincol);
586 wcursyncup(formwin);
588 else
589 wcursyncup(form->w);
590 return(E_OK);
593 /*---------------------------------------------------------------------------
594 | Facility : libnform
595 | Function : int _nc_Refresh_Current_Field(FORM * form)
597 | Description : Propagate the changes in the fields window to the
598 | window of the form.
600 | Return Values : E_OK - on success
601 | E_BAD_ARGUMENT - invalid form pointer
602 | E_SYSTEM_ERROR - general error
603 +--------------------------------------------------------------------------*/
604 NCURSES_EXPORT(int)
605 _nc_Refresh_Current_Field (FORM * form)
607 WINDOW *formwin;
608 FIELD *field;
610 if (!form)
611 RETURN(E_BAD_ARGUMENT);
613 if (!form->w || !form->current)
614 RETURN(E_SYSTEM_ERROR);
616 field = form->current;
617 formwin = Get_Form_Window(form);
619 if (field->opts & O_PUBLIC)
621 if (Is_Scroll_Field(field))
623 /* Again, in this case the fieldwin isn't derived from formwin,
624 so we have to perform a copy operation. */
625 if (Single_Line_Field(field))
626 { /* horizontal scrolling */
627 if (form->curcol < form->begincol)
628 form->begincol = form->curcol;
629 else
631 if (form->curcol >= (form->begincol + field->cols))
632 form->begincol = form->curcol - field->cols + 1;
634 copywin(form->w,
635 formwin,
637 form->begincol,
638 field->frow,
639 field->fcol,
640 field->frow,
641 field->cols + field->fcol - 1,
644 else
645 { /* A multi-line, i.e. vertical scrolling field */
646 int row_after_bottom,first_modified_row,first_unmodified_row;
648 if (field->drows > field->rows)
650 row_after_bottom = form->toprow + field->rows;
651 if (form->currow < form->toprow)
653 form->toprow = form->currow;
654 field->status |= _NEWTOP;
656 if (form->currow >= row_after_bottom)
658 form->toprow = form->currow - field->rows + 1;
659 field->status |= _NEWTOP;
661 if (field->status & _NEWTOP)
662 { /* means we have to copy whole range */
663 first_modified_row = form->toprow;
664 first_unmodified_row = first_modified_row + field->rows;
665 field->status &= ~_NEWTOP;
667 else
668 { /* we try to optimize : finding the range of touched
669 lines */
670 first_modified_row = form->toprow;
671 while(first_modified_row < row_after_bottom)
673 if (is_linetouched(form->w,first_modified_row))
674 break;
675 first_modified_row++;
677 first_unmodified_row = first_modified_row;
678 while(first_unmodified_row < row_after_bottom)
680 if (!is_linetouched(form->w,first_unmodified_row))
681 break;
682 first_unmodified_row++;
686 else
688 first_modified_row = form->toprow;
689 first_unmodified_row = first_modified_row + field->rows;
691 if (first_unmodified_row != first_modified_row)
692 copywin(form->w,
693 formwin,
694 first_modified_row,
696 field->frow + first_modified_row - form->toprow,
697 field->fcol,
698 field->frow + first_unmodified_row - form->toprow - 1,
699 field->cols + field->fcol - 1,
702 wsyncup(formwin);
704 else
705 { /* if the field-window is simply a derived window, i.e. contains
706 no invisible parts, the whole thing is trivial
708 wsyncup(form->w);
711 untouchwin(form->w);
712 return _nc_Position_Form_Cursor(form);
715 /*---------------------------------------------------------------------------
716 | Facility : libnform
717 | Function : static void Perform_Justification(
718 | FIELD * field,
719 | WINDOW * win)
721 | Description : Output field with requested justification
723 | Return Values : -
724 +--------------------------------------------------------------------------*/
725 static void Perform_Justification(FIELD * field, WINDOW * win)
727 char *bp;
728 int len;
729 int col = 0;
731 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
732 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
734 if (len>0)
736 assert(win && (field->drows == 1) && (field->dcols == field->cols));
738 switch(field->just)
740 case JUSTIFY_LEFT:
741 break;
742 case JUSTIFY_CENTER:
743 col = (field->cols - len)/2;
744 break;
745 case JUSTIFY_RIGHT:
746 col = field->cols - len;
747 break;
748 default:
749 break;
752 wmove(win,0,col);
753 waddnstr(win,bp,len);
757 /*---------------------------------------------------------------------------
758 | Facility : libnform
759 | Function : static void Undo_Justification(
760 | FIELD * field,
761 | WINDOW * win)
763 | Description : Display field without any justification, i.e.
764 | left justified
766 | Return Values : -
767 +--------------------------------------------------------------------------*/
768 static void Undo_Justification(FIELD * field, WINDOW * win)
770 char *bp;
771 int len;
773 bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
774 len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
776 if (len>0)
778 assert(win);
779 wmove(win,0,0);
780 waddnstr(win,bp,len);
784 /*---------------------------------------------------------------------------
785 | Facility : libnform
786 | Function : static bool Check_Char(
787 | FIELDTYPE * typ,
788 | int ch,
789 | TypeArgument *argp)
791 | Description : Perform a single character check for character ch
792 | according to the fieldtype instance.
794 | Return Values : TRUE - Character is valid
795 | FALSE - Character is invalid
796 +--------------------------------------------------------------------------*/
797 static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
799 if (typ)
801 if (typ->status & _LINKED_TYPE)
803 assert(argp);
804 return(
805 Check_Char(typ->left ,ch,argp->left ) ||
806 Check_Char(typ->right,ch,argp->right) );
808 else
810 if (typ->ccheck)
811 return typ->ccheck(ch,(void *)argp);
814 return (isprint((unsigned char)ch) ? TRUE : FALSE);
817 /*---------------------------------------------------------------------------
818 | Facility : libnform
819 | Function : static int Display_Or_Erase_Field(
820 | FIELD * field,
821 | bool bEraseFlag)
823 | Description : Create a subwindow for the field and display the
824 | buffer contents (apply justification if required)
825 | or simply erase the field.
827 | Return Values : E_OK - on success
828 | E_SYSTEM_ERROR - some error (typical no memory)
829 +--------------------------------------------------------------------------*/
830 static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
832 WINDOW *win;
833 WINDOW *fwin;
835 if (!field)
836 return E_SYSTEM_ERROR;
838 fwin = Get_Form_Window(field->form);
839 win = derwin(fwin,
840 field->rows,field->cols,field->frow,field->fcol);
842 if (!win)
843 return E_SYSTEM_ERROR;
844 else
846 if (field->opts & O_VISIBLE)
847 Set_Field_Window_Attributes(field,win);
848 else
849 wattrset(win,getattrs(fwin));
850 werase(win);
853 if (!bEraseFlag)
855 if (field->opts & O_PUBLIC)
857 if (Justification_Allowed(field))
858 Perform_Justification(field,win);
859 else
860 Buffer_To_Window(field,win);
862 field->status &= ~_NEWTOP;
864 wsyncup(win);
865 delwin(win);
866 return E_OK;
869 /* Macros to preset the bEraseFlag */
870 #define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
871 #define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
873 /*---------------------------------------------------------------------------
874 | Facility : libnform
875 | Function : static int Synchronize_Field(FIELD * field)
877 | Description : Synchronize the windows content with the value in
878 | the buffer.
880 | Return Values : E_OK - success
881 | E_BAD_ARGUMENT - invalid field pointer
882 | E_SYSTEM_ERROR - some severe basic error
883 +--------------------------------------------------------------------------*/
884 static int Synchronize_Field(FIELD * field)
886 FORM *form;
887 int res = E_OK;
889 if (!field)
890 return(E_BAD_ARGUMENT);
892 if (((form=field->form) != (FORM *)0)
893 && Field_Really_Appears(field))
895 if (field == form->current)
897 form->currow = form->curcol = form->toprow = form->begincol = 0;
898 werase(form->w);
900 if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
901 Undo_Justification( field, form->w );
902 else
903 Buffer_To_Window( field, form->w );
905 field->status |= _NEWTOP;
906 res = _nc_Refresh_Current_Field( form );
908 else
909 res = Display_Field( field );
911 field->status |= _CHANGED;
912 return(res);
915 /*---------------------------------------------------------------------------
916 | Facility : libnform
917 | Function : static int Synchronize_Linked_Fields(FIELD * field)
919 | Description : Propagate the Synchronize_Field function to all linked
920 | fields. The first error that occurs in the sequence
921 | of updates is the return value.
923 | Return Values : E_OK - success
924 | E_BAD_ARGUMENT - invalid field pointer
925 | E_SYSTEM_ERROR - some severe basic error
926 +--------------------------------------------------------------------------*/
927 static int Synchronize_Linked_Fields(FIELD * field)
929 FIELD *linked_field;
930 int res = E_OK;
931 int syncres;
933 if (!field)
934 return(E_BAD_ARGUMENT);
936 if (!field->link)
937 return(E_SYSTEM_ERROR);
939 for(linked_field = field->link;
940 linked_field!= field;
941 linked_field = linked_field->link )
943 if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
944 (res==E_OK))
945 res = syncres;
947 return(res);
950 /*---------------------------------------------------------------------------
951 | Facility : libnform
952 | Function : int _nc_Synchronize_Attributes(FIELD * field)
954 | Description : If a fields visual attributes have changed, this
955 | routine is called to propagate those changes to the
956 | screen.
958 | Return Values : E_OK - success
959 | E_BAD_ARGUMENT - invalid field pointer
960 | E_SYSTEM_ERROR - some severe basic error
961 +--------------------------------------------------------------------------*/
962 NCURSES_EXPORT(int)
963 _nc_Synchronize_Attributes (FIELD * field)
965 FORM *form;
966 int res = E_OK;
967 WINDOW *formwin;
969 if (!field)
970 return(E_BAD_ARGUMENT);
972 if (((form=field->form) != (FORM *)0)
973 && Field_Really_Appears(field))
975 if (form->current==field)
977 Synchronize_Buffer(form);
978 Set_Field_Window_Attributes(field,form->w);
979 werase(form->w);
980 if (field->opts & O_PUBLIC)
982 if (Justification_Allowed(field))
983 Undo_Justification(field,form->w);
984 else
985 Buffer_To_Window(field,form->w);
987 else
989 formwin = Get_Form_Window(form);
990 copywin(form->w,formwin,
991 0,0,
992 field->frow,field->fcol,
993 field->rows-1,field->cols-1,0);
994 wsyncup(formwin);
995 Buffer_To_Window(field,form->w);
996 field->status |= _NEWTOP; /* fake refresh to paint all */
997 _nc_Refresh_Current_Field(form);
1000 else
1002 res = Display_Field(field);
1005 return(res);
1008 /*---------------------------------------------------------------------------
1009 | Facility : libnform
1010 | Function : int _nc_Synchronize_Options(FIELD * field,
1011 | Field_Options newopts)
1013 | Description : If a fields options have changed, this routine is
1014 | called to propagate these changes to the screen and
1015 | to really change the behavior of the field.
1017 | Return Values : E_OK - success
1018 | E_BAD_ARGUMENT - invalid field pointer
1019 | E_SYSTEM_ERROR - some severe basic error
1020 +--------------------------------------------------------------------------*/
1021 NCURSES_EXPORT(int)
1022 _nc_Synchronize_Options
1023 (FIELD *field, Field_Options newopts)
1025 Field_Options oldopts;
1026 Field_Options changed_opts;
1027 FORM *form;
1028 int res = E_OK;
1030 if (!field)
1031 return(E_BAD_ARGUMENT);
1033 oldopts = field->opts;
1034 changed_opts = oldopts ^ newopts;
1035 field->opts = newopts;
1036 form = field->form;
1038 if (form)
1040 if (form->current == field)
1042 field->opts = oldopts;
1043 return(E_CURRENT);
1046 if (form->status & _POSTED)
1048 if ((form->curpage == field->page))
1050 if (changed_opts & O_VISIBLE)
1052 if (newopts & O_VISIBLE)
1053 res = Display_Field(field);
1054 else
1055 res = Erase_Field(field);
1057 else
1059 if ((changed_opts & O_PUBLIC) &&
1060 (newopts & O_VISIBLE))
1061 res = Display_Field(field);
1067 if (changed_opts & O_STATIC)
1069 bool single_line_field = Single_Line_Field(field);
1070 int res2 = E_OK;
1072 if (newopts & O_STATIC)
1073 { /* the field becomes now static */
1074 field->status &= ~_MAY_GROW;
1075 /* if actually we have no hidden columns, justification may
1076 occur again */
1077 if (single_line_field &&
1078 (field->cols == field->dcols) &&
1079 (field->just != NO_JUSTIFICATION) &&
1080 Field_Really_Appears(field))
1082 res2 = Display_Field(field);
1085 else
1086 { /* field is no longer static */
1087 if ((field->maxgrow==0) ||
1088 ( single_line_field && (field->dcols < field->maxgrow)) ||
1089 (!single_line_field && (field->drows < field->maxgrow)))
1091 field->status |= _MAY_GROW;
1092 /* a field with justification now changes its behavior,
1093 so we must redisplay it */
1094 if (single_line_field &&
1095 (field->just != NO_JUSTIFICATION) &&
1096 Field_Really_Appears(field))
1098 res2 = Display_Field(field);
1102 if (res2 != E_OK)
1103 res = res2;
1106 return(res);
1109 /*---------------------------------------------------------------------------
1110 | Facility : libnform
1111 | Function : int _nc_Set_Current_Field(FORM * form,
1112 | FIELD * newfield)
1114 | Description : Make the newfield the new current field.
1116 | Return Values : E_OK - success
1117 | E_BAD_ARGUMENT - invalid form or field pointer
1118 | E_SYSTEM_ERROR - some severe basic error
1119 +--------------------------------------------------------------------------*/
1120 NCURSES_EXPORT(int)
1121 _nc_Set_Current_Field
1122 (FORM *form, FIELD *newfield)
1124 FIELD *field;
1125 WINDOW *new_window;
1127 if (!form || !newfield || !form->current || (newfield->form!=form))
1128 return(E_BAD_ARGUMENT);
1130 if ( (form->status & _IN_DRIVER) )
1131 return(E_BAD_STATE);
1133 if (!(form->field))
1134 return(E_NOT_CONNECTED);
1136 field = form->current;
1138 if ((field!=newfield) ||
1139 !(form->status & _POSTED))
1141 if ((form->w) &&
1142 (field->opts & O_VISIBLE) &&
1143 (field->form->curpage == field->page))
1145 _nc_Refresh_Current_Field(form);
1146 if (field->opts & O_PUBLIC)
1148 if (field->drows > field->rows)
1150 if (form->toprow==0)
1151 field->status &= ~_NEWTOP;
1152 else
1153 field->status |= _NEWTOP;
1155 else
1157 if (Justification_Allowed(field))
1159 Window_To_Buffer(form->w,field);
1160 werase(form->w);
1161 Perform_Justification(field,form->w);
1162 wsyncup(form->w);
1166 delwin(form->w);
1167 form->w = (WINDOW *)0;
1170 field = newfield;
1172 if (Has_Invisible_Parts(field))
1173 new_window = newpad(field->drows,field->dcols);
1174 else
1175 new_window = derwin(Get_Form_Window(form),
1176 field->rows,field->cols,field->frow,field->fcol);
1178 if (!new_window)
1179 return(E_SYSTEM_ERROR);
1181 form->current = field;
1183 if (form->w)
1184 delwin(form->w);
1185 form->w = new_window;
1187 form->status &= ~_WINDOW_MODIFIED;
1188 Set_Field_Window_Attributes(field,form->w);
1190 if (Has_Invisible_Parts(field))
1192 werase(form->w);
1193 Buffer_To_Window(field,form->w);
1195 else
1197 if (Justification_Allowed(field))
1199 werase(form->w);
1200 Undo_Justification(field,form->w);
1201 wsyncup(form->w);
1205 untouchwin(form->w);
1208 form->currow = form->curcol = form->toprow = form->begincol = 0;
1209 return(E_OK);
1212 /*----------------------------------------------------------------------------
1213 Intra-Field Navigation routines
1214 --------------------------------------------------------------------------*/
1216 /*---------------------------------------------------------------------------
1217 | Facility : libnform
1218 | Function : static int IFN_Next_Character(FORM * form)
1220 | Description : Move to the next character in the field. In a multi-line
1221 | field this wraps at the end of the line.
1223 | Return Values : E_OK - success
1224 | E_REQUEST_DENIED - at the rightmost position
1225 +--------------------------------------------------------------------------*/
1226 static int IFN_Next_Character(FORM * form)
1228 FIELD *field = form->current;
1230 if ((++(form->curcol))==field->dcols)
1232 if ((++(form->currow))==field->drows)
1234 #if GROW_IF_NAVIGATE
1235 if (!Single_Line_Field(field) && Field_Grown(field,1)) {
1236 form->curcol = 0;
1237 return(E_OK);
1239 #endif
1240 form->currow--;
1241 #if GROW_IF_NAVIGATE
1242 if (Single_Line_Field(field) && Field_Grown(field,1))
1243 return(E_OK);
1244 #endif
1245 form->curcol--;
1246 return(E_REQUEST_DENIED);
1248 form->curcol = 0;
1250 return(E_OK);
1253 /*---------------------------------------------------------------------------
1254 | Facility : libnform
1255 | Function : static int IFN_Previous_Character(FORM * form)
1257 | Description : Move to the previous character in the field. In a
1258 | multi-line field this wraps and the beginning of the
1259 | line.
1261 | Return Values : E_OK - success
1262 | E_REQUEST_DENIED - at the leftmost position
1263 +--------------------------------------------------------------------------*/
1264 static int IFN_Previous_Character(FORM * form)
1266 if ((--(form->curcol))<0)
1268 if ((--(form->currow))<0)
1270 form->currow++;
1271 form->curcol++;
1272 return(E_REQUEST_DENIED);
1274 form->curcol = form->current->dcols - 1;
1276 return(E_OK);
1279 /*---------------------------------------------------------------------------
1280 | Facility : libnform
1281 | Function : static int IFN_Next_Line(FORM * form)
1283 | Description : Move to the beginning of the next line in the field
1285 | Return Values : E_OK - success
1286 | E_REQUEST_DENIED - at the last line
1287 +--------------------------------------------------------------------------*/
1288 static int IFN_Next_Line(FORM * form)
1290 FIELD *field = form->current;
1292 if ((++(form->currow))==field->drows)
1294 #if GROW_IF_NAVIGATE
1295 if (!Single_Line_Field(field) && Field_Grown(field,1))
1296 return(E_OK);
1297 #endif
1298 form->currow--;
1299 return(E_REQUEST_DENIED);
1301 form->curcol = 0;
1302 return(E_OK);
1305 /*---------------------------------------------------------------------------
1306 | Facility : libnform
1307 | Function : static int IFN_Previous_Line(FORM * form)
1309 | Description : Move to the beginning of the previous line in the field
1311 | Return Values : E_OK - success
1312 | E_REQUEST_DENIED - at the first line
1313 +--------------------------------------------------------------------------*/
1314 static int IFN_Previous_Line(FORM * form)
1316 if ( (--(form->currow)) < 0 )
1318 form->currow++;
1319 return(E_REQUEST_DENIED);
1321 form->curcol = 0;
1322 return(E_OK);
1325 /*---------------------------------------------------------------------------
1326 | Facility : libnform
1327 | Function : static int IFN_Next_Word(FORM * form)
1329 | Description : Move to the beginning of the next word in the field.
1331 | Return Values : E_OK - success
1332 | E_REQUEST_DENIED - there is no next word
1333 +--------------------------------------------------------------------------*/
1334 static int IFN_Next_Word(FORM * form)
1336 FIELD *field = form->current;
1337 char *bp = Address_Of_Current_Position_In_Buffer(form);
1338 char *s;
1339 char *t;
1341 /* We really need access to the data, so we have to synchronize */
1342 Synchronize_Buffer(form);
1344 /* Go to the first whitespace after the current position (including
1345 current position). This is then the starting point to look for the
1346 next non-blank data */
1347 s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
1348 (int)(bp - field->buf));
1350 /* Find the start of the next word */
1351 t = Get_Start_Of_Data(s,Buffer_Length(field) -
1352 (int)(s - field->buf));
1353 #if !FRIENDLY_PREV_NEXT_WORD
1354 if (s==t)
1355 return(E_REQUEST_DENIED);
1356 else
1357 #endif
1359 Adjust_Cursor_Position(form,t);
1360 return(E_OK);
1364 /*---------------------------------------------------------------------------
1365 | Facility : libnform
1366 | Function : static int IFN_Previous_Word(FORM * form)
1368 | Description : Move to the beginning of the previous word in the field.
1370 | Return Values : E_OK - success
1371 | E_REQUEST_DENIED - there is no previous word
1372 +--------------------------------------------------------------------------*/
1373 static int IFN_Previous_Word(FORM * form)
1375 FIELD *field = form->current;
1376 char *bp = Address_Of_Current_Position_In_Buffer(form);
1377 char *s;
1378 char *t;
1379 bool again = FALSE;
1381 /* We really need access to the data, so we have to synchronize */
1382 Synchronize_Buffer(form);
1384 s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
1385 /* s points now right after the last non-blank in the buffer before bp.
1386 If bp was in a word, s equals bp. In this case we must find the last
1387 whitespace in the buffer before bp and repeat the game to really find
1388 the previous word! */
1389 if (s==bp)
1390 again = TRUE;
1392 /* And next call now goes backward to look for the last whitespace
1393 before that, pointing right after this, so it points to the begin
1394 of the previous word.
1396 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1397 #if !FRIENDLY_PREV_NEXT_WORD
1398 if (s==t)
1399 return(E_REQUEST_DENIED);
1400 #endif
1401 if (again)
1402 { /* and do it again, replacing bp by t */
1403 s = After_End_Of_Data(field->buf,(int)(t - field->buf));
1404 t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1405 #if !FRIENDLY_PREV_NEXT_WORD
1406 if (s==t)
1407 return(E_REQUEST_DENIED);
1408 #endif
1410 Adjust_Cursor_Position(form,t);
1411 return(E_OK);
1414 /*---------------------------------------------------------------------------
1415 | Facility : libnform
1416 | Function : static int IFN_Beginning_Of_Field(FORM * form)
1418 | Description : Place the cursor at the first non-pad character in
1419 | the field.
1421 | Return Values : E_OK - success
1422 +--------------------------------------------------------------------------*/
1423 static int IFN_Beginning_Of_Field(FORM * form)
1425 FIELD *field = form->current;
1427 Synchronize_Buffer(form);
1428 Adjust_Cursor_Position(form,
1429 Get_Start_Of_Data(field->buf,Buffer_Length(field)));
1430 return(E_OK);
1433 /*---------------------------------------------------------------------------
1434 | Facility : libnform
1435 | Function : static int IFN_End_Of_Field(FORM * form)
1437 | Description : Place the cursor after the last non-pad character in
1438 | the field. If the field occupies the last position in
1439 | the buffer, the cursor is positioned on the last
1440 | character.
1442 | Return Values : E_OK - success
1443 +--------------------------------------------------------------------------*/
1444 static int IFN_End_Of_Field(FORM * form)
1446 FIELD *field = form->current;
1447 char *pos;
1449 Synchronize_Buffer(form);
1450 pos = After_End_Of_Data(field->buf,Buffer_Length(field));
1451 if (pos==(field->buf + Buffer_Length(field)))
1452 pos--;
1453 Adjust_Cursor_Position(form,pos);
1454 return(E_OK);
1457 /*---------------------------------------------------------------------------
1458 | Facility : libnform
1459 | Function : static int IFN_Beginning_Of_Line(FORM * form)
1461 | Description : Place the cursor on the first non-pad character in
1462 | the current line of the field.
1464 | Return Values : E_OK - success
1465 +--------------------------------------------------------------------------*/
1466 static int IFN_Beginning_Of_Line(FORM * form)
1468 FIELD *field = form->current;
1470 Synchronize_Buffer(form);
1471 Adjust_Cursor_Position(form,
1472 Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1473 field->dcols));
1474 return(E_OK);
1477 /*---------------------------------------------------------------------------
1478 | Facility : libnform
1479 | Function : static int IFN_End_Of_Line(FORM * form)
1481 | Description : Place the cursor after the last non-pad character in the
1482 | current line of the field. If the field occupies the
1483 | last column in the line, the cursor is positioned on the
1484 | last character of the line.
1486 | Return Values : E_OK - success
1487 +--------------------------------------------------------------------------*/
1488 static int IFN_End_Of_Line(FORM * form)
1490 FIELD *field = form->current;
1491 char *pos;
1492 char *bp;
1494 Synchronize_Buffer(form);
1495 bp = Address_Of_Current_Row_In_Buffer(form);
1496 pos = After_End_Of_Data(bp,field->dcols);
1497 if (pos == (bp + field->dcols))
1498 pos--;
1499 Adjust_Cursor_Position(form,pos);
1500 return(E_OK);
1503 /*---------------------------------------------------------------------------
1504 | Facility : libnform
1505 | Function : static int IFN_Left_Character(FORM * form)
1507 | Description : Move one character to the left in the current line.
1508 | This doesn't cycle.
1510 | Return Values : E_OK - success
1511 | E_REQUEST_DENIED - already in first column
1512 +--------------------------------------------------------------------------*/
1513 static int IFN_Left_Character(FORM * form)
1515 if ( (--(form->curcol)) < 0 )
1517 form->curcol++;
1518 return(E_REQUEST_DENIED);
1520 return(E_OK);
1523 /*---------------------------------------------------------------------------
1524 | Facility : libnform
1525 | Function : static int IFN_Right_Character(FORM * form)
1527 | Description : Move one character to the right in the current line.
1528 | This doesn't cycle.
1530 | Return Values : E_OK - success
1531 | E_REQUEST_DENIED - already in last column
1532 +--------------------------------------------------------------------------*/
1533 static int IFN_Right_Character(FORM * form)
1535 if ( (++(form->curcol)) == form->current->dcols )
1537 #if GROW_IF_NAVIGATE
1538 FIELD *field = form->current;
1539 if (Single_Line_Field(field) && Field_Grown(field,1))
1540 return(E_OK);
1541 #endif
1542 --(form->curcol);
1543 return(E_REQUEST_DENIED);
1545 return(E_OK);
1548 /*---------------------------------------------------------------------------
1549 | Facility : libnform
1550 | Function : static int IFN_Up_Character(FORM * form)
1552 | Description : Move one line up. This doesn't cycle through the lines
1553 | of the field.
1555 | Return Values : E_OK - success
1556 | E_REQUEST_DENIED - already in last column
1557 +--------------------------------------------------------------------------*/
1558 static int IFN_Up_Character(FORM * form)
1560 if ( (--(form->currow)) < 0 )
1562 form->currow++;
1563 return(E_REQUEST_DENIED);
1565 return(E_OK);
1568 /*---------------------------------------------------------------------------
1569 | Facility : libnform
1570 | Function : static int IFN_Down_Character(FORM * form)
1572 | Description : Move one line down. This doesn't cycle through the
1573 | lines of the field.
1575 | Return Values : E_OK - success
1576 | E_REQUEST_DENIED - already in last column
1577 +--------------------------------------------------------------------------*/
1578 static int IFN_Down_Character(FORM * form)
1580 FIELD *field = form->current;
1582 if ( (++(form->currow)) == field->drows )
1584 #if GROW_IF_NAVIGATE
1585 if (!Single_Line_Field(field) && Field_Grown(field,1))
1586 return(E_OK);
1587 #endif
1588 --(form->currow);
1589 return(E_REQUEST_DENIED);
1591 return(E_OK);
1593 /*----------------------------------------------------------------------------
1594 END of Intra-Field Navigation routines
1595 --------------------------------------------------------------------------*/
1597 /*----------------------------------------------------------------------------
1598 Vertical scrolling helper routines
1599 --------------------------------------------------------------------------*/
1601 /*---------------------------------------------------------------------------
1602 | Facility : libnform
1603 | Function : static int VSC_Generic(FORM *form, int lines)
1605 | Description : Scroll multi-line field forward (lines>0) or
1606 | backward (lines<0) this many lines.
1608 | Return Values : E_OK - success
1609 | E_REQUEST_DENIED - can't scroll
1610 +--------------------------------------------------------------------------*/
1611 static int VSC_Generic(FORM *form, int lines)
1613 FIELD *field = form->current;
1614 int res = E_REQUEST_DENIED;
1615 int rows_to_go = (lines > 0 ? lines : -lines);
1617 if (lines > 0)
1619 if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
1620 rows_to_go = (field->drows - field->rows - form->toprow);
1622 if (rows_to_go > 0)
1624 form->currow += rows_to_go;
1625 form->toprow += rows_to_go;
1626 res = E_OK;
1629 else
1631 if (rows_to_go > form->toprow)
1632 rows_to_go = form->toprow;
1634 if (rows_to_go > 0)
1636 form->currow -= rows_to_go;
1637 form->toprow -= rows_to_go;
1638 res = E_OK;
1641 return(res);
1643 /*----------------------------------------------------------------------------
1644 End of Vertical scrolling helper routines
1645 --------------------------------------------------------------------------*/
1647 /*----------------------------------------------------------------------------
1648 Vertical scrolling routines
1649 --------------------------------------------------------------------------*/
1651 /*---------------------------------------------------------------------------
1652 | Facility : libnform
1653 | Function : static int Vertical_Scrolling(
1654 | int (* const fct) (FORM *),
1655 | FORM * form)
1657 | Description : Performs the generic vertical scrolling routines.
1658 | This has to check for a multi-line field and to set
1659 | the _NEWTOP flag if scrolling really occurred.
1661 | Return Values : Propagated error code from low-level driver calls
1662 +--------------------------------------------------------------------------*/
1663 static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
1665 int res = E_REQUEST_DENIED;
1667 if (!Single_Line_Field(form->current))
1669 res = fct(form);
1670 if (res == E_OK)
1671 form->current->status |= _NEWTOP;
1673 return(res);
1676 /*---------------------------------------------------------------------------
1677 | Facility : libnform
1678 | Function : static int VSC_Scroll_Line_Forward(FORM * form)
1680 | Description : Scroll multi-line field forward a line
1682 | Return Values : E_OK - success
1683 | E_REQUEST_DENIED - no data ahead
1684 +--------------------------------------------------------------------------*/
1685 static int VSC_Scroll_Line_Forward(FORM * form)
1687 return VSC_Generic(form,1);
1690 /*---------------------------------------------------------------------------
1691 | Facility : libnform
1692 | Function : static int VSC_Scroll_Line_Backward(FORM * form)
1694 | Description : Scroll multi-line field backward a line
1696 | Return Values : E_OK - success
1697 | E_REQUEST_DENIED - no data behind
1698 +--------------------------------------------------------------------------*/
1699 static int VSC_Scroll_Line_Backward(FORM * form)
1701 return VSC_Generic(form,-1);
1704 /*---------------------------------------------------------------------------
1705 | Facility : libnform
1706 | Function : static int VSC_Scroll_Page_Forward(FORM * form)
1708 | Description : Scroll a multi-line field forward a page
1710 | Return Values : E_OK - success
1711 | E_REQUEST_DENIED - no data ahead
1712 +--------------------------------------------------------------------------*/
1713 static int VSC_Scroll_Page_Forward(FORM * form)
1715 return VSC_Generic(form,form->current->rows);
1718 /*---------------------------------------------------------------------------
1719 | Facility : libnform
1720 | Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1722 | Description : Scroll a multi-line field forward half a page
1724 | Return Values : E_OK - success
1725 | E_REQUEST_DENIED - no data ahead
1726 +--------------------------------------------------------------------------*/
1727 static int VSC_Scroll_Half_Page_Forward(FORM * form)
1729 return VSC_Generic(form,(form->current->rows + 1)/2);
1732 /*---------------------------------------------------------------------------
1733 | Facility : libnform
1734 | Function : static int VSC_Scroll_Page_Backward(FORM * form)
1736 | Description : Scroll a multi-line field backward a page
1738 | Return Values : E_OK - success
1739 | E_REQUEST_DENIED - no data behind
1740 +--------------------------------------------------------------------------*/
1741 static int VSC_Scroll_Page_Backward(FORM * form)
1743 return VSC_Generic(form, -(form->current->rows));
1746 /*---------------------------------------------------------------------------
1747 | Facility : libnform
1748 | Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
1750 | Description : Scroll a multi-line field backward half a page
1752 | Return Values : E_OK - success
1753 | E_REQUEST_DENIED - no data behind
1754 +--------------------------------------------------------------------------*/
1755 static int VSC_Scroll_Half_Page_Backward(FORM * form)
1757 return VSC_Generic(form, -((form->current->rows + 1)/2));
1759 /*----------------------------------------------------------------------------
1760 End of Vertical scrolling routines
1761 --------------------------------------------------------------------------*/
1763 /*----------------------------------------------------------------------------
1764 Horizontal scrolling helper routines
1765 --------------------------------------------------------------------------*/
1767 /*---------------------------------------------------------------------------
1768 | Facility : libnform
1769 | Function : static int HSC_Generic(FORM *form, int columns)
1771 | Description : Scroll single-line field forward (columns>0) or
1772 | backward (columns<0) this many columns.
1774 | Return Values : E_OK - success
1775 | E_REQUEST_DENIED - can't scroll
1776 +--------------------------------------------------------------------------*/
1777 static int HSC_Generic(FORM *form, int columns)
1779 FIELD *field = form->current;
1780 int res = E_REQUEST_DENIED;
1781 int cols_to_go = (columns > 0 ? columns : -columns);
1783 if (columns > 0)
1785 if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
1786 cols_to_go = field->dcols - field->cols - form->begincol;
1788 if (cols_to_go > 0)
1790 form->curcol += cols_to_go;
1791 form->begincol += cols_to_go;
1792 res = E_OK;
1795 else
1797 if ( cols_to_go > form->begincol )
1798 cols_to_go = form->begincol;
1800 if (cols_to_go > 0)
1802 form->curcol -= cols_to_go;
1803 form->begincol -= cols_to_go;
1804 res = E_OK;
1807 return(res);
1809 /*----------------------------------------------------------------------------
1810 End of Horizontal scrolling helper routines
1811 --------------------------------------------------------------------------*/
1813 /*----------------------------------------------------------------------------
1814 Horizontal scrolling routines
1815 --------------------------------------------------------------------------*/
1817 /*---------------------------------------------------------------------------
1818 | Facility : libnform
1819 | Function : static int Horizontal_Scrolling(
1820 | int (* const fct) (FORM *),
1821 | FORM * form)
1823 | Description : Performs the generic horizontal scrolling routines.
1824 | This has to check for a single-line field.
1826 | Return Values : Propagated error code from low-level driver calls
1827 +--------------------------------------------------------------------------*/
1828 static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
1830 if (Single_Line_Field(form->current))
1831 return fct(form);
1832 else
1833 return(E_REQUEST_DENIED);
1836 /*---------------------------------------------------------------------------
1837 | Facility : libnform
1838 | Function : static int HSC_Scroll_Char_Forward(FORM * form)
1840 | Description : Scroll single-line field forward a character
1842 | Return Values : E_OK - success
1843 | E_REQUEST_DENIED - no data ahead
1844 +--------------------------------------------------------------------------*/
1845 static int HSC_Scroll_Char_Forward(FORM *form)
1847 return HSC_Generic(form,1);
1850 /*---------------------------------------------------------------------------
1851 | Facility : libnform
1852 | Function : static int HSC_Scroll_Char_Backward(FORM * form)
1854 | Description : Scroll single-line field backward a character
1856 | Return Values : E_OK - success
1857 | E_REQUEST_DENIED - no data behind
1858 +--------------------------------------------------------------------------*/
1859 static int HSC_Scroll_Char_Backward(FORM *form)
1861 return HSC_Generic(form,-1);
1864 /*---------------------------------------------------------------------------
1865 | Facility : libnform
1866 | Function : static int HSC_Horizontal_Line_Forward(FORM* form)
1868 | Description : Scroll single-line field forward a line
1870 | Return Values : E_OK - success
1871 | E_REQUEST_DENIED - no data ahead
1872 +--------------------------------------------------------------------------*/
1873 static int HSC_Horizontal_Line_Forward(FORM * form)
1875 return HSC_Generic(form,form->current->cols);
1878 /*---------------------------------------------------------------------------
1879 | Facility : libnform
1880 | Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
1882 | Description : Scroll single-line field forward half a line
1884 | Return Values : E_OK - success
1885 | E_REQUEST_DENIED - no data ahead
1886 +--------------------------------------------------------------------------*/
1887 static int HSC_Horizontal_Half_Line_Forward(FORM * form)
1889 return HSC_Generic(form,(form->current->cols + 1)/2);
1892 /*---------------------------------------------------------------------------
1893 | Facility : libnform
1894 | Function : static int HSC_Horizontal_Line_Backward(FORM* form)
1896 | Description : Scroll single-line field backward a line
1898 | Return Values : E_OK - success
1899 | E_REQUEST_DENIED - no data behind
1900 +--------------------------------------------------------------------------*/
1901 static int HSC_Horizontal_Line_Backward(FORM * form)
1903 return HSC_Generic(form,-(form->current->cols));
1906 /*---------------------------------------------------------------------------
1907 | Facility : libnform
1908 | Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
1910 | Description : Scroll single-line field backward half a line
1912 | Return Values : E_OK - success
1913 | E_REQUEST_DENIED - no data behind
1914 +--------------------------------------------------------------------------*/
1915 static int HSC_Horizontal_Half_Line_Backward(FORM * form)
1917 return HSC_Generic(form,-((form->current->cols + 1)/2));
1920 /*----------------------------------------------------------------------------
1921 End of Horizontal scrolling routines
1922 --------------------------------------------------------------------------*/
1924 /*----------------------------------------------------------------------------
1925 Helper routines for Field Editing
1926 --------------------------------------------------------------------------*/
1928 /*---------------------------------------------------------------------------
1929 | Facility : libnform
1930 | Function : static bool Is_There_Room_For_A_Line(FORM * form)
1932 | Description : Check whether or not there is enough room in the
1933 | buffer to enter a whole line.
1935 | Return Values : TRUE - there is enough space
1936 | FALSE - there is not enough space
1937 +--------------------------------------------------------------------------*/
1938 INLINE static bool Is_There_Room_For_A_Line(FORM * form)
1940 FIELD *field = form->current;
1941 char *begin_of_last_line, *s;
1943 Synchronize_Buffer(form);
1944 begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
1945 s = After_End_Of_Data(begin_of_last_line,field->dcols);
1946 return ((s==begin_of_last_line) ? TRUE : FALSE);
1949 /*---------------------------------------------------------------------------
1950 | Facility : libnform
1951 | Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1953 | Description : Checks whether or not there is room for a new character
1954 | in the current line.
1956 | Return Values : TRUE - there is room
1957 | FALSE - there is not enough room (line full)
1958 +--------------------------------------------------------------------------*/
1959 INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1961 int last_char_in_line;
1963 wmove(form->w,form->currow,form->current->dcols-1);
1964 last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
1965 wmove(form->w,form->currow,form->curcol);
1966 return (((last_char_in_line == form->current->pad) ||
1967 is_blank(last_char_in_line)) ? TRUE : FALSE);
1970 #define There_Is_No_Room_For_A_Char_In_Line(f) \
1971 !Is_There_Room_For_A_Char_In_Line(f)
1973 /*---------------------------------------------------------------------------
1974 | Facility : libnform
1975 | Function : static int Insert_String(
1976 | FORM * form,
1977 | int row,
1978 | char *txt,
1979 | int len )
1981 | Description : Insert the 'len' characters beginning at pointer 'txt'
1982 | into the 'row' of the 'form'. The insertion occurs
1983 | on the beginning of the row, all other characters are
1984 | moved to the right. After the text a pad character will
1985 | be inserted to separate the text from the rest. If
1986 | necessary the insertion moves characters on the next
1987 | line to make place for the requested insertion string.
1989 | Return Values : E_OK - success
1990 | E_REQUEST_DENIED -
1991 | E_SYSTEM_ERROR - system error
1992 +--------------------------------------------------------------------------*/
1993 static int Insert_String(FORM *form, int row, char *txt, int len)
1995 FIELD *field = form->current;
1996 char *bp = Address_Of_Row_In_Buffer(field,row);
1997 int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
1998 int freelen = field->dcols - datalen;
1999 int requiredlen = len+1;
2000 char *split;
2001 int result = E_REQUEST_DENIED;
2002 const char *Space = " ";
2004 if (freelen >= requiredlen)
2006 wmove(form->w,row,0);
2007 winsnstr(form->w,txt,len);
2008 wmove(form->w,row,len);
2009 winsnstr(form->w,Space,1);
2010 return E_OK;
2012 else
2013 { /* we have to move characters on the next line. If we are on the
2014 last line this may work, if the field is growable */
2015 if ((row == (field->drows - 1)) && Growable(field))
2017 if (!Field_Grown(field,1))
2018 return(E_SYSTEM_ERROR);
2019 /* !!!Side-Effect : might be changed due to growth!!! */
2020 bp = Address_Of_Row_In_Buffer(field,row);
2023 if (row < (field->drows - 1))
2025 split = After_Last_Whitespace_Character(bp,
2026 (int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
2027 requiredlen) - bp));
2028 /* split points now to the first character of the portion of the
2029 line that must be moved to the next line */
2030 datalen = (int)(split-bp); /* + freelen has to stay on this line */
2031 freelen = field->dcols - (datalen + freelen); /* for the next line */
2033 if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
2035 wmove(form->w,row,datalen);
2036 wclrtoeol(form->w);
2037 wmove(form->w,row,0);
2038 winsnstr(form->w,txt,len);
2039 wmove(form->w,row,len);
2040 winsnstr(form->w,Space,1);
2041 return E_OK;
2044 return(result);
2048 /*---------------------------------------------------------------------------
2049 | Facility : libnform
2050 | Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2051 | FORM * form)
2053 | Description : If a character has been entered into a field, it may
2054 | be that wrapping has to occur. This routine checks
2055 | whether or not wrapping is required and if so, performs
2056 | the wrapping.
2058 | Return Values : E_OK - no wrapping required or wrapping
2059 | was successful
2060 | E_REQUEST_DENIED -
2061 | E_SYSTEM_ERROR - some system error
2062 +--------------------------------------------------------------------------*/
2063 static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
2065 FIELD *field = form->current;
2066 int result = E_REQUEST_DENIED;
2067 bool Last_Row = ((field->drows - 1) == form->currow);
2069 if ( (field->opts & O_WRAP) && /* wrapping wanted */
2070 (!Single_Line_Field(field)) && /* must be multi-line */
2071 (There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
2072 (!Last_Row || Growable(field)) ) /* there are more lines*/
2074 char *bp;
2075 char *split;
2076 int chars_to_be_wrapped;
2077 int chars_to_remain_on_line;
2078 if (Last_Row)
2079 { /* the above logic already ensures, that in this case the field
2080 is growable */
2081 if (!Field_Grown(field,1))
2082 return E_SYSTEM_ERROR;
2084 bp = Address_Of_Current_Row_In_Buffer(form);
2085 Window_To_Buffer(form->w,field);
2086 split = After_Last_Whitespace_Character(bp,field->dcols);
2087 /* split points to the first character of the sequence to be brought
2088 on the next line */
2089 chars_to_remain_on_line = (int)(split - bp);
2090 chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2091 if (chars_to_remain_on_line > 0)
2093 if ((result=Insert_String(form,form->currow+1,split,
2094 chars_to_be_wrapped)) == E_OK)
2096 wmove(form->w,form->currow,chars_to_remain_on_line);
2097 wclrtoeol(form->w);
2098 if (form->curcol >= chars_to_remain_on_line)
2100 form->currow++;
2101 form->curcol -= chars_to_remain_on_line;
2103 return E_OK;
2106 else
2107 return E_OK;
2108 if (result!=E_OK)
2110 wmove(form->w,form->currow,form->curcol);
2111 wdelch(form->w);
2112 Window_To_Buffer(form->w,field);
2113 result = E_REQUEST_DENIED;
2116 else
2117 result = E_OK; /* wrapping was not necessary */
2118 return(result);
2121 /*----------------------------------------------------------------------------
2122 Field Editing routines
2123 --------------------------------------------------------------------------*/
2125 /*---------------------------------------------------------------------------
2126 | Facility : libnform
2127 | Function : static int Field_Editing(
2128 | int (* const fct) (FORM *),
2129 | FORM * form)
2131 | Description : Generic routine for field editing requests. The driver
2132 | routines are only called for editable fields, the
2133 | _WINDOW_MODIFIED flag is set if editing occurred.
2134 | This is somewhat special due to the overload semantics
2135 | of the NEW_LINE and DEL_PREV requests.
2137 | Return Values : Error code from low level drivers.
2138 +--------------------------------------------------------------------------*/
2139 static int Field_Editing(int (* const fct) (FORM *), FORM * form)
2141 int res = E_REQUEST_DENIED;
2143 /* We have to deal here with the specific case of the overloaded
2144 behavior of New_Line and Delete_Previous requests.
2145 They may end up in navigational requests if we are on the first
2146 character in a field. But navigation is also allowed on non-
2147 editable fields.
2149 if ((fct==FE_Delete_Previous) &&
2150 (form->opts & O_BS_OVERLOAD) &&
2151 First_Position_In_Current_Field(form) )
2153 res = Inter_Field_Navigation(FN_Previous_Field,form);
2155 else
2157 if (fct==FE_New_Line)
2159 if ((form->opts & O_NL_OVERLOAD) &&
2160 First_Position_In_Current_Field(form))
2162 res = Inter_Field_Navigation(FN_Next_Field,form);
2164 else
2165 /* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2166 res = fct(form);
2168 else
2170 /* From now on, everything must be editable */
2171 if (form->current->opts & O_EDIT)
2173 res = fct(form);
2174 if (res==E_OK)
2175 form->status |= _WINDOW_MODIFIED;
2179 return res;
2182 /*---------------------------------------------------------------------------
2183 | Facility : libnform
2184 | Function : static int FE_New_Line(FORM * form)
2186 | Description : Perform a new line request. This is rather complex
2187 | compared to other routines in this code due to the
2188 | rather difficult to understand description in the
2189 | manuals.
2191 | Return Values : E_OK - success
2192 | E_REQUEST_DENIED - new line not allowed
2193 | E_SYSTEM_ERROR - system error
2194 +--------------------------------------------------------------------------*/
2195 static int FE_New_Line(FORM * form)
2197 FIELD *field = form->current;
2198 char *bp, *t;
2199 bool Last_Row = ((field->drows - 1)==form->currow);
2201 if (form->status & _OVLMODE)
2203 if (Last_Row &&
2204 (!(Growable(field) && !Single_Line_Field(field))))
2206 if (!(form->opts & O_NL_OVERLOAD))
2207 return(E_REQUEST_DENIED);
2208 wmove(form->w,form->currow,form->curcol);
2209 wclrtoeol(form->w);
2210 /* we have to set this here, although it is also
2211 handled in the generic routine. The reason is,
2212 that FN_Next_Field may fail, but the form is
2213 definitively changed */
2214 form->status |= _WINDOW_MODIFIED;
2215 return Inter_Field_Navigation(FN_Next_Field,form);
2217 else
2219 if (Last_Row && !Field_Grown(field,1))
2220 { /* N.B.: due to the logic in the 'if', LastRow==TRUE
2221 means here that the field is growable and not
2222 a single-line field */
2223 return(E_SYSTEM_ERROR);
2225 wmove(form->w,form->currow,form->curcol);
2226 wclrtoeol(form->w);
2227 form->currow++;
2228 form->curcol = 0;
2229 form->status |= _WINDOW_MODIFIED;
2230 return(E_OK);
2233 else
2234 { /* Insert Mode */
2235 if (Last_Row &&
2236 !(Growable(field) && !Single_Line_Field(field)))
2238 if (!(form->opts & O_NL_OVERLOAD))
2239 return(E_REQUEST_DENIED);
2240 return Inter_Field_Navigation(FN_Next_Field,form);
2242 else
2244 bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2246 if (!(May_Do_It || Growable(field)))
2247 return(E_REQUEST_DENIED);
2248 if (!May_Do_It && !Field_Grown(field,1))
2249 return(E_SYSTEM_ERROR);
2251 bp= Address_Of_Current_Position_In_Buffer(form);
2252 t = After_End_Of_Data(bp,field->dcols - form->curcol);
2253 wmove(form->w,form->currow,form->curcol);
2254 wclrtoeol(form->w);
2255 form->currow++;
2256 form->curcol=0;
2257 wmove(form->w,form->currow,form->curcol);
2258 winsertln(form->w);
2259 waddnstr(form->w,bp,(int)(t-bp));
2260 form->status |= _WINDOW_MODIFIED;
2261 return E_OK;
2266 /*---------------------------------------------------------------------------
2267 | Facility : libnform
2268 | Function : static int FE_Insert_Character(FORM * form)
2270 | Description : Insert blank character at the cursor position
2272 | Return Values : E_OK
2273 | E_REQUEST_DENIED
2274 +--------------------------------------------------------------------------*/
2275 static int FE_Insert_Character(FORM * form)
2277 FIELD *field = form->current;
2278 int result = E_REQUEST_DENIED;
2280 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2282 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2284 if (There_Is_Room ||
2285 ((Single_Line_Field(field) && Growable(field))))
2287 if (!There_Is_Room && !Field_Grown(field,1))
2288 result = E_SYSTEM_ERROR;
2289 else
2291 winsch(form->w,(chtype)C_BLANK);
2292 result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2296 return result;
2299 /*---------------------------------------------------------------------------
2300 | Facility : libnform
2301 | Function : static int FE_Insert_Line(FORM * form)
2303 | Description : Insert a blank line at the cursor position
2305 | Return Values : E_OK - success
2306 | E_REQUEST_DENIED - line can not be inserted
2307 +--------------------------------------------------------------------------*/
2308 static int FE_Insert_Line(FORM * form)
2310 FIELD *field = form->current;
2311 int result = E_REQUEST_DENIED;
2313 if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2315 bool Maybe_Done = (form->currow!=(field->drows-1)) &&
2316 Is_There_Room_For_A_Line(form);
2318 if (!Single_Line_Field(field) &&
2319 (Maybe_Done || Growable(field)))
2321 if (!Maybe_Done && !Field_Grown(field,1))
2322 result = E_SYSTEM_ERROR;
2323 else
2325 form->curcol = 0;
2326 winsertln(form->w);
2327 result = E_OK;
2331 return result;
2334 /*---------------------------------------------------------------------------
2335 | Facility : libnform
2336 | Function : static int FE_Delete_Character(FORM * form)
2338 | Description : Delete character at the cursor position
2340 | Return Values : E_OK - success
2341 +--------------------------------------------------------------------------*/
2342 static int FE_Delete_Character(FORM * form)
2344 wmove(form->w,form->currow,form->curcol);
2345 wdelch(form->w);
2346 return E_OK;
2349 /*---------------------------------------------------------------------------
2350 | Facility : libnform
2351 | Function : static int FE_Delete_Previous(FORM * form)
2353 | Description : Delete character before cursor. Again this is a rather
2354 | difficult piece compared to others due to the overloading
2355 | semantics of backspace.
2356 | N.B.: The case of overloaded BS on first field position
2357 | is already handled in the generic routine.
2359 | Return Values : E_OK - success
2360 | E_REQUEST_DENIED - Character can't be deleted
2361 +--------------------------------------------------------------------------*/
2362 static int FE_Delete_Previous(FORM * form)
2364 FIELD *field = form->current;
2366 if (First_Position_In_Current_Field(form))
2367 return E_REQUEST_DENIED;
2369 if ( (--(form->curcol))<0 )
2371 char *this_line, *prev_line, *prev_end, *this_end;
2373 form->curcol++;
2374 if (form->status & _OVLMODE)
2375 return E_REQUEST_DENIED;
2377 prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
2378 this_line = Address_Of_Row_In_Buffer(field,(form->currow));
2379 Synchronize_Buffer(form);
2380 prev_end = After_End_Of_Data(prev_line,field->dcols);
2381 this_end = After_End_Of_Data(this_line,field->dcols);
2382 if ((int)(this_end-this_line) >
2383 (field->cols-(int)(prev_end-prev_line)))
2384 return E_REQUEST_DENIED;
2385 wmove(form->w,form->currow,form->curcol);
2386 wdeleteln(form->w);
2387 Adjust_Cursor_Position(form,prev_end);
2388 wmove(form->w,form->currow,form->curcol);
2389 waddnstr(form->w,this_line,(int)(this_end-this_line));
2391 else
2393 wmove(form->w,form->currow,form->curcol);
2394 wdelch(form->w);
2396 return E_OK;
2399 /*---------------------------------------------------------------------------
2400 | Facility : libnform
2401 | Function : static int FE_Delete_Line(FORM * form)
2403 | Description : Delete line at cursor position.
2405 | Return Values : E_OK - success
2406 +--------------------------------------------------------------------------*/
2407 static int FE_Delete_Line(FORM * form)
2409 form->curcol = 0;
2410 wdeleteln(form->w);
2411 return E_OK;
2414 /*---------------------------------------------------------------------------
2415 | Facility : libnform
2416 | Function : static int FE_Delete_Word(FORM * form)
2418 | Description : Delete word at cursor position
2420 | Return Values : E_OK - success
2421 | E_REQUEST_DENIED - failure
2422 +--------------------------------------------------------------------------*/
2423 static int FE_Delete_Word(FORM * form)
2425 FIELD *field = form->current;
2426 char *bp = Address_Of_Current_Row_In_Buffer(form);
2427 char *ep = bp + field->dcols;
2428 char *cp = bp + form->curcol;
2429 char *s;
2431 Synchronize_Buffer(form);
2432 if (is_blank(*cp))
2433 return E_REQUEST_DENIED; /* not in word */
2435 /* move cursor to begin of word and erase to end of screen-line */
2436 Adjust_Cursor_Position(form,
2437 After_Last_Whitespace_Character(bp,form->curcol));
2438 wmove(form->w,form->currow,form->curcol);
2439 wclrtoeol(form->w);
2441 /* skip over word in buffer */
2442 s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
2443 /* to begin of next word */
2444 s = Get_Start_Of_Data(s,(int)(ep - s));
2445 if ( (s!=cp) && !is_blank(*s))
2447 /* copy remaining line to window */
2448 waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
2450 return E_OK;
2453 /*---------------------------------------------------------------------------
2454 | Facility : libnform
2455 | Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2457 | Description : Clear to end of current line.
2459 | Return Values : E_OK - success
2460 +--------------------------------------------------------------------------*/
2461 static int FE_Clear_To_End_Of_Line(FORM * form)
2463 wmove(form->w,form->currow,form->curcol);
2464 wclrtoeol(form->w);
2465 return E_OK;
2468 /*---------------------------------------------------------------------------
2469 | Facility : libnform
2470 | Function : static int FE_Clear_To_End_Of_Field(FORM * form)
2472 | Description : Clear to end of field.
2474 | Return Values : E_OK - success
2475 +--------------------------------------------------------------------------*/
2476 static int FE_Clear_To_End_Of_Field(FORM * form)
2478 wmove(form->w,form->currow,form->curcol);
2479 wclrtobot(form->w);
2480 return E_OK;
2483 /*---------------------------------------------------------------------------
2484 | Facility : libnform
2485 | Function : static int FE_Clear_Field(FORM * form)
2487 | Description : Clear entire field.
2489 | Return Values : E_OK - success
2490 +--------------------------------------------------------------------------*/
2491 static int FE_Clear_Field(FORM * form)
2493 form->currow = form->curcol = 0;
2494 werase(form->w);
2495 return E_OK;
2497 /*----------------------------------------------------------------------------
2498 END of Field Editing routines
2499 --------------------------------------------------------------------------*/
2501 /*----------------------------------------------------------------------------
2502 Edit Mode routines
2503 --------------------------------------------------------------------------*/
2505 /*---------------------------------------------------------------------------
2506 | Facility : libnform
2507 | Function : static int EM_Overlay_Mode(FORM * form)
2509 | Description : Switch to overlay mode.
2511 | Return Values : E_OK - success
2512 +--------------------------------------------------------------------------*/
2513 static int EM_Overlay_Mode(FORM * form)
2515 form->status |= _OVLMODE;
2516 return E_OK;
2519 /*---------------------------------------------------------------------------
2520 | Facility : libnform
2521 | Function : static int EM_Insert_Mode(FORM * form)
2523 | Description : Switch to insert mode
2525 | Return Values : E_OK - success
2526 +--------------------------------------------------------------------------*/
2527 static int EM_Insert_Mode(FORM * form)
2529 form->status &= ~_OVLMODE;
2530 return E_OK;
2533 /*----------------------------------------------------------------------------
2534 END of Edit Mode routines
2535 --------------------------------------------------------------------------*/
2537 /*----------------------------------------------------------------------------
2538 Helper routines for Choice Requests
2539 --------------------------------------------------------------------------*/
2541 /*---------------------------------------------------------------------------
2542 | Facility : libnform
2543 | Function : static bool Next_Choice(
2544 | FIELDTYPE * typ,
2545 | FIELD * field,
2546 | TypeArgument *argp)
2548 | Description : Get the next field choice. For linked types this is
2549 | done recursively.
2551 | Return Values : TRUE - next choice successfully retrieved
2552 | FALSE - couldn't retrieve next choice
2553 +--------------------------------------------------------------------------*/
2554 static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
2556 if (!typ || !(typ->status & _HAS_CHOICE))
2557 return FALSE;
2559 if (typ->status & _LINKED_TYPE)
2561 assert(argp);
2562 return(
2563 Next_Choice(typ->left ,field,argp->left) ||
2564 Next_Choice(typ->right,field,argp->right) );
2566 else
2568 assert(typ->next);
2569 return typ->next(field,(void *)argp);
2573 /*---------------------------------------------------------------------------
2574 | Facility : libnform
2575 | Function : static bool Previous_Choice(
2576 | FIELDTYPE * typ,
2577 | FIELD * field,
2578 | TypeArgument *argp)
2580 | Description : Get the previous field choice. For linked types this
2581 | is done recursively.
2583 | Return Values : TRUE - previous choice successfully retrieved
2584 | FALSE - couldn't retrieve previous choice
2585 +--------------------------------------------------------------------------*/
2586 static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2588 if (!typ || !(typ->status & _HAS_CHOICE))
2589 return FALSE;
2591 if (typ->status & _LINKED_TYPE)
2593 assert(argp);
2594 return(
2595 Previous_Choice(typ->left ,field,argp->left) ||
2596 Previous_Choice(typ->right,field,argp->right));
2598 else
2600 assert(typ->prev);
2601 return typ->prev(field,(void *)argp);
2604 /*----------------------------------------------------------------------------
2605 End of Helper routines for Choice Requests
2606 --------------------------------------------------------------------------*/
2608 /*----------------------------------------------------------------------------
2609 Routines for Choice Requests
2610 --------------------------------------------------------------------------*/
2612 /*---------------------------------------------------------------------------
2613 | Facility : libnform
2614 | Function : static int CR_Next_Choice(FORM * form)
2616 | Description : Get the next field choice.
2618 | Return Values : E_OK - success
2619 | E_REQUEST_DENIED - next choice couldn't be retrieved
2620 +--------------------------------------------------------------------------*/
2621 static int CR_Next_Choice(FORM * form)
2623 FIELD *field = form->current;
2624 Synchronize_Buffer(form);
2625 return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2626 E_OK : E_REQUEST_DENIED);
2629 /*---------------------------------------------------------------------------
2630 | Facility : libnform
2631 | Function : static int CR_Previous_Choice(FORM * form)
2633 | Description : Get the previous field choice.
2635 | Return Values : E_OK - success
2636 | E_REQUEST_DENIED - prev. choice couldn't be retrieved
2637 +--------------------------------------------------------------------------*/
2638 static int CR_Previous_Choice(FORM * form)
2640 FIELD *field = form->current;
2641 Synchronize_Buffer(form);
2642 return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2643 E_OK : E_REQUEST_DENIED);
2645 /*----------------------------------------------------------------------------
2646 End of Routines for Choice Requests
2647 --------------------------------------------------------------------------*/
2649 /*----------------------------------------------------------------------------
2650 Helper routines for Field Validations.
2651 --------------------------------------------------------------------------*/
2653 /*---------------------------------------------------------------------------
2654 | Facility : libnform
2655 | Function : static bool Check_Field(
2656 | FIELDTYPE * typ,
2657 | FIELD * field,
2658 | TypeArgument * argp)
2660 | Description : Check the field according to its fieldtype and its
2661 | actual arguments. For linked fieldtypes this is done
2662 | recursively.
2664 | Return Values : TRUE - field is valid
2665 | FALSE - field is invalid.
2666 +--------------------------------------------------------------------------*/
2667 static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2669 if (typ)
2671 if (field->opts & O_NULLOK)
2673 char *bp = field->buf;
2674 assert(bp);
2675 while(is_blank(*bp))
2676 { bp++; }
2677 if (*bp == '\0')
2678 return TRUE;
2681 if (typ->status & _LINKED_TYPE)
2683 assert(argp);
2684 return(
2685 Check_Field(typ->left ,field,argp->left ) ||
2686 Check_Field(typ->right,field,argp->right) );
2688 else
2690 if (typ->fcheck)
2691 return typ->fcheck(field,(void *)argp);
2694 return TRUE;
2697 /*---------------------------------------------------------------------------
2698 | Facility : libnform
2699 | Function : bool _nc_Internal_Validation(FORM * form )
2701 | Description : Validate the current field of the form.
2703 | Return Values : TRUE - field is valid
2704 | FALSE - field is invalid
2705 +--------------------------------------------------------------------------*/
2706 NCURSES_EXPORT(bool)
2707 _nc_Internal_Validation (FORM *form)
2709 FIELD *field;
2711 field = form->current;
2713 Synchronize_Buffer(form);
2714 if ((form->status & _FCHECK_REQUIRED) ||
2715 (!(field->opts & O_PASSOK)))
2717 if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
2718 return FALSE;
2719 form->status &= ~_FCHECK_REQUIRED;
2720 field->status |= _CHANGED;
2721 Synchronize_Linked_Fields(field);
2723 return TRUE;
2725 /*----------------------------------------------------------------------------
2726 End of Helper routines for Field Validations.
2727 --------------------------------------------------------------------------*/
2729 /*----------------------------------------------------------------------------
2730 Routines for Field Validation.
2731 --------------------------------------------------------------------------*/
2733 /*---------------------------------------------------------------------------
2734 | Facility : libnform
2735 | Function : static int FV_Validation(FORM * form)
2737 | Description : Validate the current field of the form.
2739 | Return Values : E_OK - field valid
2740 | E_INVALID_FIELD - field not valid
2741 +--------------------------------------------------------------------------*/
2742 static int FV_Validation(FORM * form)
2744 if (_nc_Internal_Validation(form))
2745 return E_OK;
2746 else
2747 return E_INVALID_FIELD;
2749 /*----------------------------------------------------------------------------
2750 End of routines for Field Validation.
2751 --------------------------------------------------------------------------*/
2753 /*----------------------------------------------------------------------------
2754 Helper routines for Inter-Field Navigation
2755 --------------------------------------------------------------------------*/
2757 /*---------------------------------------------------------------------------
2758 | Facility : libnform
2759 | Function : static FIELD *Next_Field_On_Page(FIELD * field)
2761 | Description : Get the next field after the given field on the current
2762 | page. The order of fields is the one defined by the
2763 | fields array. Only visible and active fields are
2764 | counted.
2766 | Return Values : Pointer to the next field.
2767 +--------------------------------------------------------------------------*/
2768 INLINE static FIELD *Next_Field_On_Page(FIELD * field)
2770 FORM *form = field->form;
2771 FIELD **field_on_page = &form->field[field->index];
2772 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2773 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2777 field_on_page =
2778 (field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
2779 if (Field_Is_Selectable(*field_on_page))
2780 break;
2781 } while(field!=(*field_on_page));
2782 return(*field_on_page);
2785 /*---------------------------------------------------------------------------
2786 | Facility : libnform
2787 | Function : FIELD* _nc_First_Active_Field(FORM * form)
2789 | Description : Get the first active field on the current page,
2790 | if there are such. If there are none, get the first
2791 | visible field on the page. If there are also none,
2792 | we return the first field on page and hope the best.
2794 | Return Values : Pointer to calculated field.
2795 +--------------------------------------------------------------------------*/
2796 NCURSES_EXPORT(FIELD*)
2797 _nc_First_Active_Field (FORM * form)
2799 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2800 FIELD *proposed = Next_Field_On_Page(*last_on_page);
2802 if (proposed == *last_on_page)
2803 { /* there might be the special situation, where there is no
2804 active and visible field on the current page. We then select
2805 the first visible field on this readonly page
2807 if (Field_Is_Not_Selectable(proposed))
2809 FIELD **field = &form->field[proposed->index];
2810 FIELD **first = &form->field[form->page[form->curpage].pmin];
2814 field = (field==last_on_page) ? first : field + 1;
2815 if (((*field)->opts & O_VISIBLE))
2816 break;
2817 } while(proposed!=(*field));
2819 proposed = *field;
2821 if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
2822 { /* This means, there is also no visible field on the page.
2823 So we propose the first one and hope the very best...
2824 Some very clever user has designed a readonly and invisible
2825 page on this form.
2827 proposed = *first;
2831 return(proposed);
2834 /*---------------------------------------------------------------------------
2835 | Facility : libnform
2836 | Function : static FIELD *Previous_Field_On_Page(FIELD * field)
2838 | Description : Get the previous field before the given field on the
2839 | current page. The order of fields is the one defined by
2840 | the fields array. Only visible and active fields are
2841 | counted.
2843 | Return Values : Pointer to the previous field.
2844 +--------------------------------------------------------------------------*/
2845 INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
2847 FORM *form = field->form;
2848 FIELD **field_on_page = &form->field[field->index];
2849 FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2850 FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2854 field_on_page =
2855 (field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
2856 if (Field_Is_Selectable(*field_on_page))
2857 break;
2858 } while(field!=(*field_on_page));
2860 return (*field_on_page);
2863 /*---------------------------------------------------------------------------
2864 | Facility : libnform
2865 | Function : static FIELD *Sorted_Next_Field(FIELD * field)
2867 | Description : Get the next field after the given field on the current
2868 | page. The order of fields is the one defined by the
2869 | (row,column) geometry, rows are major.
2871 | Return Values : Pointer to the next field.
2872 +--------------------------------------------------------------------------*/
2873 INLINE static FIELD *Sorted_Next_Field(FIELD * field)
2875 FIELD *field_on_page = field;
2879 field_on_page = field_on_page->snext;
2880 if (Field_Is_Selectable(field_on_page))
2881 break;
2882 } while(field_on_page!=field);
2884 return (field_on_page);
2887 /*---------------------------------------------------------------------------
2888 | Facility : libnform
2889 | Function : static FIELD *Sorted_Previous_Field(FIELD * field)
2891 | Description : Get the previous field before the given field on the
2892 | current page. The order of fields is the one defined
2893 | by the (row,column) geometry, rows are major.
2895 | Return Values : Pointer to the previous field.
2896 +--------------------------------------------------------------------------*/
2897 INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
2899 FIELD *field_on_page = field;
2903 field_on_page = field_on_page->sprev;
2904 if (Field_Is_Selectable(field_on_page))
2905 break;
2906 } while(field_on_page!=field);
2908 return (field_on_page);
2911 /*---------------------------------------------------------------------------
2912 | Facility : libnform
2913 | Function : static FIELD *Left_Neighbor_Field(FIELD * field)
2915 | Description : Get the left neighbor of the field on the same line
2916 | and the same page. Cycles through the line.
2918 | Return Values : Pointer to left neighbor field.
2919 +--------------------------------------------------------------------------*/
2920 INLINE static FIELD *Left_Neighbor_Field(FIELD * field)
2922 FIELD *field_on_page = field;
2924 /* For a field that has really a left neighbor, the while clause
2925 immediately fails and the loop is left, positioned at the right
2926 neighbor. Otherwise we cycle backwards through the sorted field list
2927 until we enter the same line (from the right end).
2931 field_on_page = Sorted_Previous_Field(field_on_page);
2932 } while(field_on_page->frow != field->frow);
2934 return (field_on_page);
2937 /*---------------------------------------------------------------------------
2938 | Facility : libnform
2939 | Function : static FIELD *Right_Neighbor_Field(FIELD * field)
2941 | Description : Get the right neighbor of the field on the same line
2942 | and the same page.
2944 | Return Values : Pointer to right neighbor field.
2945 +--------------------------------------------------------------------------*/
2946 INLINE static FIELD *Right_Neighbor_Field(FIELD * field)
2948 FIELD *field_on_page = field;
2950 /* See the comments on Left_Neighbor_Field to understand how it works */
2953 field_on_page = Sorted_Next_Field(field_on_page);
2954 } while(field_on_page->frow != field->frow);
2956 return (field_on_page);
2959 /*---------------------------------------------------------------------------
2960 | Facility : libnform
2961 | Function : static FIELD *Upper_Neighbor_Field(FIELD * field)
2963 | Description : Because of the row-major nature of sorting the fields,
2964 | it is more difficult to define whats the upper neighbor
2965 | field really means. We define that it must be on a
2966 | 'previous' line (cyclic order!) and is the rightmost
2967 | field laying on the left side of the given field. If
2968 | this set is empty, we take the first field on the line.
2970 | Return Values : Pointer to the upper neighbor field.
2971 +--------------------------------------------------------------------------*/
2972 static FIELD *Upper_Neighbor_Field(FIELD * field)
2974 FIELD *field_on_page = field;
2975 int frow = field->frow;
2976 int fcol = field->fcol;
2978 /* Walk back to the 'previous' line. The second term in the while clause
2979 just guarantees that we stop if we cycled through the line because
2980 there might be no 'previous' line if the page has just one line.
2984 field_on_page = Sorted_Previous_Field(field_on_page);
2985 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
2987 if (field_on_page->frow!=frow)
2988 { /* We really found a 'previous' line. We are positioned at the
2989 rightmost field on this line */
2990 frow = field_on_page->frow;
2992 /* We walk to the left as long as we are really right of the
2993 field. */
2994 while(field_on_page->frow==frow && field_on_page->fcol>fcol)
2995 field_on_page = Sorted_Previous_Field(field_on_page);
2997 /* If we wrapped, just go to the right which is the first field on
2998 the row */
2999 if (field_on_page->frow!=frow)
3000 field_on_page = Sorted_Next_Field(field_on_page);
3003 return (field_on_page);
3006 /*---------------------------------------------------------------------------
3007 | Facility : libnform
3008 | Function : static FIELD *Down_Neighbor_Field(FIELD * field)
3010 | Description : Because of the row-major nature of sorting the fields,
3011 | its more difficult to define whats the down neighbor
3012 | field really means. We define that it must be on a
3013 | 'next' line (cyclic order!) and is the leftmost
3014 | field laying on the right side of the given field. If
3015 | this set is empty, we take the last field on the line.
3017 | Return Values : Pointer to the upper neighbor field.
3018 +--------------------------------------------------------------------------*/
3019 static FIELD *Down_Neighbor_Field(FIELD * field)
3021 FIELD *field_on_page = field;
3022 int frow = field->frow;
3023 int fcol = field->fcol;
3025 /* Walk forward to the 'next' line. The second term in the while clause
3026 just guarantees that we stop if we cycled through the line because
3027 there might be no 'next' line if the page has just one line.
3031 field_on_page = Sorted_Next_Field(field_on_page);
3032 } while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3034 if (field_on_page->frow!=frow)
3035 { /* We really found a 'next' line. We are positioned at the rightmost
3036 field on this line */
3037 frow = field_on_page->frow;
3039 /* We walk to the right as long as we are really left of the
3040 field. */
3041 while(field_on_page->frow==frow && field_on_page->fcol<fcol)
3042 field_on_page = Sorted_Next_Field(field_on_page);
3044 /* If we wrapped, just go to the left which is the last field on
3045 the row */
3046 if (field_on_page->frow!=frow)
3047 field_on_page = Sorted_Previous_Field(field_on_page);
3050 return(field_on_page);
3053 /*----------------------------------------------------------------------------
3054 Inter-Field Navigation routines
3055 --------------------------------------------------------------------------*/
3057 /*---------------------------------------------------------------------------
3058 | Facility : libnform
3059 | Function : static int Inter_Field_Navigation(
3060 | int (* const fct) (FORM *),
3061 | FORM * form)
3063 | Description : Generic behavior for changing the current field, the
3064 | field is left and a new field is entered. So the field
3065 | must be validated and the field init/term hooks must
3066 | be called.
3068 | Return Values : E_OK - success
3069 | E_INVALID_FIELD - field is invalid
3070 | some other - error from subordinate call
3071 +--------------------------------------------------------------------------*/
3072 static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
3074 int res;
3076 if (!_nc_Internal_Validation(form))
3077 res = E_INVALID_FIELD;
3078 else
3080 Call_Hook(form,fieldterm);
3081 res = fct(form);
3082 Call_Hook(form,fieldinit);
3084 return res;
3087 /*---------------------------------------------------------------------------
3088 | Facility : libnform
3089 | Function : static int FN_Next_Field(FORM * form)
3091 | Description : Move to the next field on the current page of the form
3093 | Return Values : E_OK - success
3094 | != E_OK - error from subordinate call
3095 +--------------------------------------------------------------------------*/
3096 static int FN_Next_Field(FORM * form)
3098 return _nc_Set_Current_Field(form,
3099 Next_Field_On_Page(form->current));
3102 /*---------------------------------------------------------------------------
3103 | Facility : libnform
3104 | Function : static int FN_Previous_Field(FORM * form)
3106 | Description : Move to the previous field on the current page of the
3107 | form
3109 | Return Values : E_OK - success
3110 | != E_OK - error from subordinate call
3111 +--------------------------------------------------------------------------*/
3112 static int FN_Previous_Field(FORM * form)
3114 return _nc_Set_Current_Field(form,
3115 Previous_Field_On_Page(form->current));
3118 /*---------------------------------------------------------------------------
3119 | Facility : libnform
3120 | Function : static int FN_First_Field(FORM * form)
3122 | Description : Move to the first field on the current page of the form
3124 | Return Values : E_OK - success
3125 | != E_OK - error from subordinate call
3126 +--------------------------------------------------------------------------*/
3127 static int FN_First_Field(FORM * form)
3129 return _nc_Set_Current_Field(form,
3130 Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
3133 /*---------------------------------------------------------------------------
3134 | Facility : libnform
3135 | Function : static int FN_Last_Field(FORM * form)
3137 | Description : Move to the last field on the current page of the form
3139 | Return Values : E_OK - success
3140 | != E_OK - error from subordinate call
3141 +--------------------------------------------------------------------------*/
3142 static int FN_Last_Field(FORM * form)
3144 return
3145 _nc_Set_Current_Field(form,
3146 Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
3149 /*---------------------------------------------------------------------------
3150 | Facility : libnform
3151 | Function : static int FN_Sorted_Next_Field(FORM * form)
3153 | Description : Move to the sorted next field on the current page
3154 | of the form.
3156 | Return Values : E_OK - success
3157 | != E_OK - error from subordinate call
3158 +--------------------------------------------------------------------------*/
3159 static int FN_Sorted_Next_Field(FORM * form)
3161 return _nc_Set_Current_Field(form,
3162 Sorted_Next_Field(form->current));
3165 /*---------------------------------------------------------------------------
3166 | Facility : libnform
3167 | Function : static int FN_Sorted_Previous_Field(FORM * form)
3169 | Description : Move to the sorted previous field on the current page
3170 | of the form.
3172 | Return Values : E_OK - success
3173 | != E_OK - error from subordinate call
3174 +--------------------------------------------------------------------------*/
3175 static int FN_Sorted_Previous_Field(FORM * form)
3177 return _nc_Set_Current_Field(form,
3178 Sorted_Previous_Field(form->current));
3181 /*---------------------------------------------------------------------------
3182 | Facility : libnform
3183 | Function : static int FN_Sorted_First_Field(FORM * form)
3185 | Description : Move to the sorted first field on the current page
3186 | of the form.
3188 | Return Values : E_OK - success
3189 | != E_OK - error from subordinate call
3190 +--------------------------------------------------------------------------*/
3191 static int FN_Sorted_First_Field(FORM * form)
3193 return _nc_Set_Current_Field(form,
3194 Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
3197 /*---------------------------------------------------------------------------
3198 | Facility : libnform
3199 | Function : static int FN_Sorted_Last_Field(FORM * form)
3201 | Description : Move to the sorted last field on the current page
3202 | of the form.
3204 | Return Values : E_OK - success
3205 | != E_OK - error from subordinate call
3206 +--------------------------------------------------------------------------*/
3207 static int FN_Sorted_Last_Field(FORM * form)
3209 return _nc_Set_Current_Field(form,
3210 Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
3213 /*---------------------------------------------------------------------------
3214 | Facility : libnform
3215 | Function : static int FN_Left_Field(FORM * form)
3217 | Description : Get the field on the left of the current field on the
3218 | same line and the same page. Cycles through the line.
3220 | Return Values : E_OK - success
3221 | != E_OK - error from subordinate call
3222 +--------------------------------------------------------------------------*/
3223 static int FN_Left_Field(FORM * form)
3225 return _nc_Set_Current_Field(form,
3226 Left_Neighbor_Field(form->current));
3229 /*---------------------------------------------------------------------------
3230 | Facility : libnform
3231 | Function : static int FN_Right_Field(FORM * form)
3233 | Description : Get the field on the right of the current field on the
3234 | same line and the same page. Cycles through the line.
3236 | Return Values : E_OK - success
3237 | != E_OK - error from subordinate call
3238 +--------------------------------------------------------------------------*/
3239 static int FN_Right_Field(FORM * form)
3241 return _nc_Set_Current_Field(form,
3242 Right_Neighbor_Field(form->current));
3245 /*---------------------------------------------------------------------------
3246 | Facility : libnform
3247 | Function : static int FN_Up_Field(FORM * form)
3249 | Description : Get the upper neighbor of the current field. This
3250 | cycles through the page. See the comments of the
3251 | Upper_Neighbor_Field function to understand how
3252 | 'upper' is defined.
3254 | Return Values : E_OK - success
3255 | != E_OK - error from subordinate call
3256 +--------------------------------------------------------------------------*/
3257 static int FN_Up_Field(FORM * form)
3259 return _nc_Set_Current_Field(form,
3260 Upper_Neighbor_Field(form->current));
3263 /*---------------------------------------------------------------------------
3264 | Facility : libnform
3265 | Function : static int FN_Down_Field(FORM * form)
3267 | Description : Get the down neighbor of the current field. This
3268 | cycles through the page. See the comments of the
3269 | Down_Neighbor_Field function to understand how
3270 | 'down' is defined.
3272 | Return Values : E_OK - success
3273 | != E_OK - error from subordinate call
3274 +--------------------------------------------------------------------------*/
3275 static int FN_Down_Field(FORM * form)
3277 return _nc_Set_Current_Field(form,
3278 Down_Neighbor_Field(form->current));
3280 /*----------------------------------------------------------------------------
3281 END of Field Navigation routines
3282 --------------------------------------------------------------------------*/
3284 /*----------------------------------------------------------------------------
3285 Helper routines for Page Navigation
3286 --------------------------------------------------------------------------*/
3288 /*---------------------------------------------------------------------------
3289 | Facility : libnform
3290 | Function : int _nc_Set_Form_Page(FORM * form,
3291 | int page,
3292 | FIELD * field)
3294 | Description : Make the given page number the current page and make
3295 | the given field the current field on the page. If
3296 | for the field NULL is given, make the first field on
3297 | the page the current field. The routine acts only
3298 | if the requested page is not the current page.
3300 | Return Values : E_OK - success
3301 | != E_OK - error from subordinate call
3302 +--------------------------------------------------------------------------*/
3303 NCURSES_EXPORT(int)
3304 _nc_Set_Form_Page
3305 (FORM * form, int page, FIELD * field)
3307 int res = E_OK;
3309 if ((form->curpage!=page))
3311 FIELD *last_field, *field_on_page;
3313 werase(Get_Form_Window(form));
3314 form->curpage = page;
3315 last_field = field_on_page = form->field[form->page[page].smin];
3318 if (field_on_page->opts & O_VISIBLE)
3319 if ((res=Display_Field(field_on_page))!=E_OK)
3320 return(res);
3321 field_on_page = field_on_page->snext;
3322 } while(field_on_page != last_field);
3324 if (field)
3325 res = _nc_Set_Current_Field(form,field);
3326 else
3327 /* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
3328 because this is already executed in a page navigation
3329 context that contains field navigation
3331 res = FN_First_Field(form);
3333 return(res);
3336 /*---------------------------------------------------------------------------
3337 | Facility : libnform
3338 | Function : static int Next_Page_Number(const FORM * form)
3340 | Description : Calculate the page number following the current page
3341 | number. This cycles if the highest page number is
3342 | reached.
3344 | Return Values : The next page number
3345 +--------------------------------------------------------------------------*/
3346 INLINE static int Next_Page_Number(const FORM * form)
3348 return (form->curpage + 1) % form->maxpage;
3351 /*---------------------------------------------------------------------------
3352 | Facility : libnform
3353 | Function : static int Previous_Page_Number(const FORM * form)
3355 | Description : Calculate the page number before the current page
3356 | number. This cycles if the first page number is
3357 | reached.
3359 | Return Values : The previous page number
3360 +--------------------------------------------------------------------------*/
3361 INLINE static int Previous_Page_Number(const FORM * form)
3363 return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
3366 /*----------------------------------------------------------------------------
3367 Page Navigation routines
3368 --------------------------------------------------------------------------*/
3370 /*---------------------------------------------------------------------------
3371 | Facility : libnform
3372 | Function : static int Page_Navigation(
3373 | int (* const fct) (FORM *),
3374 | FORM * form)
3376 | Description : Generic behavior for changing a page. This means
3377 | that the field is left and a new field is entered.
3378 | So the field must be validated and the field init/term
3379 | hooks must be called. Because also the page is changed,
3380 | the forms init/term hooks must be called also.
3382 | Return Values : E_OK - success
3383 | E_INVALID_FIELD - field is invalid
3384 | some other - error from subordinate call
3385 +--------------------------------------------------------------------------*/
3386 static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
3388 int res;
3390 if (!_nc_Internal_Validation(form))
3391 res = E_INVALID_FIELD;
3392 else
3394 Call_Hook(form,fieldterm);
3395 Call_Hook(form,formterm);
3396 res = fct(form);
3397 Call_Hook(form,forminit);
3398 Call_Hook(form,fieldinit);
3400 return res;
3403 /*---------------------------------------------------------------------------
3404 | Facility : libnform
3405 | Function : static int PN_Next_Page(FORM * form)
3407 | Description : Move to the next page of the form
3409 | Return Values : E_OK - success
3410 | != E_OK - error from subordinate call
3411 +--------------------------------------------------------------------------*/
3412 static int PN_Next_Page(FORM * form)
3414 return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
3417 /*---------------------------------------------------------------------------
3418 | Facility : libnform
3419 | Function : static int PN_Previous_Page(FORM * form)
3421 | Description : Move to the previous page of the form
3423 | Return Values : E_OK - success
3424 | != E_OK - error from subordinate call
3425 +--------------------------------------------------------------------------*/
3426 static int PN_Previous_Page(FORM * form)
3428 return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
3431 /*---------------------------------------------------------------------------
3432 | Facility : libnform
3433 | Function : static int PN_First_Page(FORM * form)
3435 | Description : Move to the first page of the form
3437 | Return Values : E_OK - success
3438 | != E_OK - error from subordinate call
3439 +--------------------------------------------------------------------------*/
3440 static int PN_First_Page(FORM * form)
3442 return _nc_Set_Form_Page(form,0,(FIELD *)0);
3445 /*---------------------------------------------------------------------------
3446 | Facility : libnform
3447 | Function : static int PN_Last_Page(FORM * form)
3449 | Description : Move to the last page of the form
3451 | Return Values : E_OK - success
3452 | != E_OK - error from subordinate call
3453 +--------------------------------------------------------------------------*/
3454 static int PN_Last_Page(FORM * form)
3456 return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
3458 /*----------------------------------------------------------------------------
3459 END of Field Navigation routines
3460 --------------------------------------------------------------------------*/
3462 /*----------------------------------------------------------------------------
3463 Helper routines for the core form driver.
3464 --------------------------------------------------------------------------*/
3466 /*---------------------------------------------------------------------------
3467 | Facility : libnform
3468 | Function : static int Data_Entry(FORM * form,int c)
3470 | Description : Enter character c into at the current position of the
3471 | current field of the form.
3473 | Return Values : E_OK -
3474 | E_REQUEST_DENIED -
3475 | E_SYSTEM_ERROR -
3476 +--------------------------------------------------------------------------*/
3477 static int Data_Entry(FORM * form, int c)
3479 FIELD *field = form->current;
3480 int result = E_REQUEST_DENIED;
3482 if ( (field->opts & O_EDIT)
3483 #if FIX_FORM_INACTIVE_BUG
3484 && (field->opts & O_ACTIVE)
3485 #endif
3488 if ( (field->opts & O_BLANK) &&
3489 First_Position_In_Current_Field(form) &&
3490 !(form->status & _FCHECK_REQUIRED) &&
3491 !(form->status & _WINDOW_MODIFIED) )
3492 werase(form->w);
3494 if (form->status & _OVLMODE)
3496 waddch(form->w,(chtype)c);
3498 else /* no _OVLMODE */
3500 bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
3502 if (!(There_Is_Room ||
3503 ((Single_Line_Field(field) && Growable(field)))))
3504 return E_REQUEST_DENIED;
3506 if (!There_Is_Room && !Field_Grown(field,1))
3507 return E_SYSTEM_ERROR;
3509 winsch(form->w,(chtype)c);
3512 if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
3514 bool End_Of_Field= (((field->drows-1)==form->currow) &&
3515 ((field->dcols-1)==form->curcol));
3516 form->status |= _WINDOW_MODIFIED;
3517 if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3518 result = Inter_Field_Navigation(FN_Next_Field,form);
3519 else
3521 if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
3522 result = E_SYSTEM_ERROR;
3523 else
3525 IFN_Next_Character(form);
3526 result = E_OK;
3531 return result;
3534 /* Structure to describe the binding of a request code to a function.
3535 The member keycode codes the request value as well as the generic
3536 routine to use for the request. The code for the generic routine
3537 is coded in the upper 16 Bits while the request code is coded in
3538 the lower 16 bits.
3540 In terms of C++ you might think of a request as a class with a
3541 virtual method "perform". The different types of request are
3542 derived from this base class and overload (or not) the base class
3543 implementation of perform.
3545 typedef struct {
3546 int keycode; /* must be at least 32 bit: hi:mode, lo: key */
3547 int (*cmd)(FORM *); /* low level driver routine for this key */
3548 } Binding_Info;
3550 /* You may see this is the class-id of the request type class */
3551 #define ID_PN (0x00000000) /* Page navigation */
3552 #define ID_FN (0x00010000) /* Inter-Field navigation */
3553 #define ID_IFN (0x00020000) /* Intra-Field navigation */
3554 #define ID_VSC (0x00030000) /* Vertical Scrolling */
3555 #define ID_HSC (0x00040000) /* Horizontal Scrolling */
3556 #define ID_FE (0x00050000) /* Field Editing */
3557 #define ID_EM (0x00060000) /* Edit Mode */
3558 #define ID_FV (0x00070000) /* Field Validation */
3559 #define ID_CH (0x00080000) /* Choice */
3560 #define ID_Mask (0xffff0000)
3561 #define Key_Mask (0x0000ffff)
3562 #define ID_Shft (16)
3564 /* This array holds all the Binding Infos */
3565 static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
3567 { REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
3568 { REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
3569 { REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
3570 { REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
3572 { REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
3573 { REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
3574 { REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
3575 { REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
3576 { REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
3577 { REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
3578 { REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
3579 { REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
3580 { REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
3581 { REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
3582 { REQ_UP_FIELD |ID_FN ,FN_Up_Field},
3583 { REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
3585 { REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
3586 { REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
3587 { REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
3588 { REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
3589 { REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
3590 { REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
3591 { REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
3592 { REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
3593 { REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
3594 { REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
3595 { REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
3596 { REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
3597 { REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
3598 { REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
3600 { REQ_NEW_LINE |ID_FE ,FE_New_Line},
3601 { REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
3602 { REQ_INS_LINE |ID_FE ,FE_Insert_Line},
3603 { REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
3604 { REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
3605 { REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
3606 { REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
3607 { REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
3608 { REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Field},
3609 { REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
3611 { REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
3612 { REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
3614 { REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
3615 { REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
3616 { REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
3617 { REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
3618 { REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
3619 { REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
3621 { REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
3622 { REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
3623 { REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
3624 { REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
3625 { REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
3626 { REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
3628 { REQ_VALIDATION |ID_FV ,FV_Validation},
3630 { REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
3631 { REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
3634 /*---------------------------------------------------------------------------
3635 | Facility : libnform
3636 | Function : int form_driver(FORM * form,int c)
3638 | Description : This is the workhorse of the forms system. It checks
3639 | to determine whether the character c is a request or
3640 | data. If it is a request, the form driver executes
3641 | the request and returns the result. If it is data
3642 | (printable character), it enters the data into the
3643 | current position in the current field. If it is not
3644 | recognized, the form driver assumes it is an application
3645 | defined command and returns E_UNKNOWN_COMMAND.
3646 | Application defined command should be defined relative
3647 | to MAX_FORM_COMMAND, the maximum value of a request.
3649 | Return Values : E_OK - success
3650 | E_SYSTEM_ERROR - system error
3651 | E_BAD_ARGUMENT - an argument is incorrect
3652 | E_NOT_POSTED - form is not posted
3653 | E_INVALID_FIELD - field contents are invalid
3654 | E_BAD_STATE - called from inside a hook routine
3655 | E_REQUEST_DENIED - request failed
3656 | E_UNKNOWN_COMMAND - command not known
3657 +--------------------------------------------------------------------------*/
3658 NCURSES_EXPORT(int)
3659 form_driver (FORM * form, int c)
3661 const Binding_Info* BI = (Binding_Info *)0;
3662 int res = E_UNKNOWN_COMMAND;
3664 if (!form)
3665 RETURN(E_BAD_ARGUMENT);
3667 if (!(form->field))
3668 RETURN(E_NOT_CONNECTED);
3670 assert(form->page);
3672 if (c==FIRST_ACTIVE_MAGIC)
3674 form->current = _nc_First_Active_Field(form);
3675 return E_OK;
3678 assert(form->current &&
3679 form->current->buf &&
3680 (form->current->form == form)
3683 if ( form->status & _IN_DRIVER )
3684 RETURN(E_BAD_STATE);
3686 if ( !( form->status & _POSTED ) )
3687 RETURN(E_NOT_POSTED);
3689 if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
3690 ((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
3691 BI = &(bindings[c-MIN_FORM_COMMAND]);
3693 if (BI)
3695 typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
3696 static const Generic_Method Generic_Methods[] =
3698 Page_Navigation, /* overloaded to call field&form hooks */
3699 Inter_Field_Navigation, /* overloaded to call field hooks */
3700 NULL, /* Intra-Field is generic */
3701 Vertical_Scrolling, /* Overloaded to check multi-line */
3702 Horizontal_Scrolling, /* Overloaded to check single-line */
3703 Field_Editing, /* Overloaded to mark modification */
3704 NULL, /* Edit Mode is generic */
3705 NULL, /* Field Validation is generic */
3706 NULL /* Choice Request is generic */
3708 size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
3709 size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
3711 if ( (method >= nMethods) || !(BI->cmd) )
3712 res = E_SYSTEM_ERROR;
3713 else
3715 Generic_Method fct = Generic_Methods[method];
3716 if (fct)
3717 res = fct(BI->cmd,form);
3718 else
3719 res = (BI->cmd)(form);
3722 else
3724 if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
3725 isprint((unsigned char)c) &&
3726 Check_Char(form->current->type,c,
3727 (TypeArgument *)(form->current->arg)))
3728 res = Data_Entry(form,c);
3730 _nc_Refresh_Current_Field(form);
3731 RETURN(res);
3734 /*----------------------------------------------------------------------------
3735 Field-Buffer manipulation routines.
3736 The effects of setting a buffer is tightly coupled to the core of the form
3737 driver logic. This is especially true in the case of growable fields.
3738 So I don't separate this into an own module.
3739 --------------------------------------------------------------------------*/
3741 /*---------------------------------------------------------------------------
3742 | Facility : libnform
3743 | Function : int set_field_buffer(FIELD *field,
3744 | int buffer, char *value)
3746 | Description : Set the given buffer of the field to the given value.
3747 | Buffer 0 stores the displayed content of the field.
3748 | For dynamic fields this may grow the fieldbuffers if
3749 | the length of the value exceeds the current buffer
3750 | length. For buffer 0 only printable values are allowed.
3751 | For static fields, the value needs not to be zero ter-
3752 | minated. It is copied up to the length of the buffer.
3754 | Return Values : E_OK - success
3755 | E_BAD_ARGUMENT - invalid argument
3756 | E_SYSTEM_ERROR - system error
3757 +--------------------------------------------------------------------------*/
3758 NCURSES_EXPORT(int)
3759 set_field_buffer
3760 (FIELD * field, int buffer, const char * value)
3762 char *s, *p;
3763 int res = E_OK;
3764 unsigned int len;
3766 if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
3767 RETURN(E_BAD_ARGUMENT);
3769 len = Buffer_Length(field);
3771 if (buffer==0)
3773 const char *v;
3774 unsigned int i = 0;
3776 for(v=value; *v && (i<len); v++,i++)
3778 if (!isprint((unsigned char)*v))
3779 RETURN(E_BAD_ARGUMENT);
3783 if (Growable(field))
3785 /* for a growable field we must assume zero terminated strings, because
3786 somehow we have to detect the length of what should be copied.
3788 unsigned int vlen = strlen(value);
3789 if (vlen > len)
3791 if (!Field_Grown(field,
3792 (int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
3793 RETURN(E_SYSTEM_ERROR);
3795 /* in this case we also have to check, whether or not the remaining
3796 characters in value are also printable for buffer 0. */
3797 if (buffer==0)
3799 unsigned int i;
3801 for(i=len; i<vlen; i++)
3802 if (!isprint((unsigned char)value[i]))
3803 RETURN(E_BAD_ARGUMENT);
3805 len = vlen;
3809 p = Address_Of_Nth_Buffer(field,buffer);
3811 #if HAVE_MEMCCPY
3812 s = (char *) memccpy(p, value, 0, len);
3813 #else
3814 for(s=(char *)value; *s && (s < (value+len)); s++)
3815 p[s-value] = *s;
3816 if (s < (value+len))
3818 p[s-value] = *s++;
3819 s = p + (s-value);
3821 else
3822 s=(char *)0;
3823 #endif
3825 if (s)
3826 { /* this means, value was null terminated and not greater than the
3827 buffer. We have to pad with blanks. Please note that due to memccpy
3828 logic s points after the terminating null. */
3829 s--; /* now we point to the terminator. */
3830 assert(len >= (unsigned int)(s-p));
3831 if (len > (unsigned int)(s-p))
3832 memset(s,C_BLANK,len-(unsigned int)(s-p));
3835 if (buffer==0)
3837 int syncres;
3838 if (((syncres=Synchronize_Field( field ))!=E_OK) &&
3839 (res==E_OK))
3840 res = syncres;
3841 if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
3842 (res==E_OK))
3843 res = syncres;
3845 RETURN(res);
3848 /*---------------------------------------------------------------------------
3849 | Facility : libnform
3850 | Function : char *field_buffer(const FIELD *field,int buffer)
3852 | Description : Return the address of the buffer for the field.
3854 | Return Values : Pointer to buffer or NULL if arguments were invalid.
3855 +--------------------------------------------------------------------------*/
3856 NCURSES_EXPORT(char *)
3857 field_buffer (const FIELD * field, int buffer)
3859 if (field && (buffer >= 0) && (buffer <= field->nbuf))
3860 return Address_Of_Nth_Buffer(field,buffer);
3861 else
3862 return (char *)0;
3865 /* frm_driver.c ends here */