Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Source/CursesDialog/form/frm_driver.c
5020 views
1
/****************************************************************************
2
* Copyright (c) 1998 Free Software Foundation, Inc. *
3
* *
4
* Permission is hereby granted, free of charge, to any person obtaining a *
5
* copy of this software and associated documentation files (the *
6
* "Software"), to deal in the Software without restriction, including *
7
* without limitation the rights to use, copy, modify, merge, publish, *
8
* distribute, distribute with modifications, sublicense, and/or sell *
9
* copies of the Software, and to permit persons to whom the Software is *
10
* furnished to do so, subject to the following conditions: *
11
* *
12
* The above copyright notice and this permission notice shall be included *
13
* in all copies or substantial portions of the Software. *
14
* *
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22
* *
23
* Except as contained in this notice, the name(s) of the above copyright *
24
* holders shall not be used in advertising or otherwise to promote the *
25
* sale, use or other dealings in this Software without prior written *
26
* authorization. *
27
****************************************************************************/
28
29
/****************************************************************************
30
* Author: Juergen Pfeifer <[email protected]> 1995,1997 *
31
****************************************************************************/
32
#include "form.priv.h"
33
34
/* AIX seems to define this */
35
#undef lines
36
#undef columns
37
38
MODULE_ID("$Id$")
39
40
/* These declarations are missing from curses.h on some platforms. */
41
extern int winnstr(WINDOW *, char *, int);
42
#if defined(__DECCXX_VER) || (defined(__GNUC__) && defined(__osf__))
43
extern int waddnstr(WINDOW *,const char *const,int);
44
extern void wbkgdset(WINDOW *,chtype);
45
#ifndef untouchwin
46
extern int untouchwin(WINDOW *);
47
#endif
48
extern void wcursyncup(WINDOW *);
49
extern int copywin(const WINDOW*,WINDOW*,int,int,int,int,int,int,int);
50
extern bool is_linetouched(WINDOW *,int);
51
extern void wsyncup(WINDOW *);
52
extern WINDOW *derwin(WINDOW *,int,int,int,int);
53
extern int winsnstr(WINDOW *, const char *,int);
54
extern int winsdelln(WINDOW *,int);
55
#endif
56
57
/*----------------------------------------------------------------------------
58
This is the core module of the form library. It contains the majority
59
of the driver routines as well as the form_driver function.
60
61
Essentially this module is nearly the whole library. This is because
62
all the functions in this module depends on some others in the module,
63
so it makes no sense to split them into separate files because they
64
will always be linked together. The only acceptable concern is turnaround
65
time for this module, but now we have all Pentiums or Riscs, so what!
66
67
The driver routines are grouped into nine generic categories:
68
69
a) Page Navigation ( all functions prefixed by PN_ )
70
The current page of the form is left and some new page is
71
entered.
72
b) Inter-Field Navigation ( all functions prefixed by FN_ )
73
The current field of the form is left and some new field is
74
entered.
75
c) Intra-Field Navigation ( all functions prefixed by IFN_ )
76
The current position in the current field is changed.
77
d) Vertical Scrolling ( all functions prefixed by VSC_ )
78
Esseantially this is a specialization of Intra-Field navigation.
79
It has to check for a multi-line field.
80
e) Horizontal Scrolling ( all functions prefixed by HSC_ )
81
Esseantially this is a specialization of Intra-Field navigation.
82
It has to check for a single-line field.
83
f) Field Editing ( all functions prefixed by FE_ )
84
The content of the current field is changed
85
g) Edit Mode requests ( all functions prefixed by EM_ )
86
Switching between insert and overlay mode
87
h) Field-Validation requests ( all functions prefixed by FV_ )
88
Perform verifications of the field.
89
i) Choice requests ( all functions prefixed by CR_ )
90
Requests to enumerate possible field values
91
--------------------------------------------------------------------------*/
92
93
/*----------------------------------------------------------------------------
94
Some remarks on the placements of assert() macros :
95
I use them only on "strategic" places, i.e. top level entries where
96
I want to make sure that things are set correctly. Throughout subordinate
97
routines I omit them mostly.
98
--------------------------------------------------------------------------*/
99
100
/*
101
Some options that may effect compatibility in behavior to SVr4 forms,
102
but they are here to allow a more intuitive and user friendly behaviour of
103
our form implementation. This doesn't affect the API, so we feel it is
104
uncritical.
105
106
The initial implementation tries to stay very close with the behaviour
107
of the original SVr4 implementation, although in some areas it is quite
108
clear that this isn't the most appropriate way. As far as possible this
109
sources will allow you to build a forms lib that behaves quite similar
110
to SVr4, but now and in the future we will give you better options.
111
Perhaps at some time we will make this configurable at runtime.
112
*/
113
114
/* Implement a more user-friendly previous/next word behaviour */
115
#define FRIENDLY_PREV_NEXT_WORD (1)
116
/* Fix the wrong behaviour for forms with all fields inactive */
117
#define FIX_FORM_INACTIVE_BUG (1)
118
/* Allow dynamic field growth also when navigating past the end */
119
#define GROW_IF_NAVIGATE (1)
120
121
/*----------------------------------------------------------------------------
122
Forward references to some internally used static functions
123
--------------------------------------------------------------------------*/
124
static int Inter_Field_Navigation ( int (* const fct) (FORM *), FORM * form );
125
static int FN_Next_Field (FORM * form);
126
static int FN_Previous_Field (FORM * form);
127
static int FE_New_Line(FORM *);
128
static int FE_Delete_Previous(FORM *);
129
130
/*----------------------------------------------------------------------------
131
Macro Definitions.
132
133
Some Remarks on that: I use the convention to use UPPERCASE for constants
134
defined by Macros. If I provide a macro as a kind of inline routine to
135
provide some logic, I use my Upper_Lower case style.
136
--------------------------------------------------------------------------*/
137
138
/* Calculate the position of a single row in a field buffer */
139
#define Position_Of_Row_In_Buffer(field,row) ((row)*(field)->dcols)
140
141
/* Calculate start address for the fields buffer# N */
142
#define Address_Of_Nth_Buffer(field,N) \
143
((field)->buf + (N)*(1+Buffer_Length(field)))
144
145
/* Calculate the start address of the row in the fields specified buffer# N */
146
#define Address_Of_Row_In_Nth_Buffer(field,N,row) \
147
(Address_Of_Nth_Buffer(field,N) + Position_Of_Row_In_Buffer(field,row))
148
149
/* Calculate the start address of the row in the fields primary buffer */
150
#define Address_Of_Row_In_Buffer(field,row) \
151
Address_Of_Row_In_Nth_Buffer(field,0,row)
152
153
/* Calculate the start address of the row in the forms current field
154
buffer# N */
155
#define Address_Of_Current_Row_In_Nth_Buffer(form,N) \
156
Address_Of_Row_In_Nth_Buffer((form)->current,N,(form)->currow)
157
158
/* Calculate the start address of the row in the forms current field
159
primary buffer */
160
#define Address_Of_Current_Row_In_Buffer(form) \
161
Address_Of_Current_Row_In_Nth_Buffer(form,0)
162
163
/* Calculate the address of the cursor in the forms current field
164
primary buffer */
165
#define Address_Of_Current_Position_In_Nth_Buffer(form,N) \
166
(Address_Of_Current_Row_In_Nth_Buffer(form,N) + (form)->curcol)
167
168
/* Calculate the address of the cursor in the forms current field
169
buffer# N */
170
#define Address_Of_Current_Position_In_Buffer(form) \
171
Address_Of_Current_Position_In_Nth_Buffer(form,0)
172
173
/* Logic to decide whether or not a field is actually a field with
174
vertical or horizontal scrolling */
175
#define Is_Scroll_Field(field) \
176
(((field)->drows > (field)->rows) || \
177
((field)->dcols > (field)->cols))
178
179
/* Logic to decide whether or not a field needs to have an individual window
180
instead of a derived window because it contains invisible parts.
181
This is true for non-public fields and for scrollable fields. */
182
#define Has_Invisible_Parts(field) \
183
(!((field)->opts & O_PUBLIC) || \
184
Is_Scroll_Field(field))
185
186
/* Logic to decide whether or not a field needs justification */
187
#define Justification_Allowed(field) \
188
(((field)->just != NO_JUSTIFICATION) && \
189
(Single_Line_Field(field)) && \
190
(((field)->dcols == (field)->cols) && \
191
((field)->opts & O_STATIC)) )
192
193
/* Logic to determine whether or not a dynamic field may still grow */
194
#define Growable(field) ((field)->status & _MAY_GROW)
195
196
/* Macro to set the attributes for a fields window */
197
#define Set_Field_Window_Attributes(field,win) \
198
( wbkgdset((win),(chtype)((field)->pad | (field)->back)), \
199
wattrset((win),(field)->fore) )
200
201
/* Logic to decide whether or not a field really appears on the form */
202
#define Field_Really_Appears(field) \
203
((field->form) &&\
204
(field->form->status & _POSTED) &&\
205
(field->opts & O_VISIBLE) &&\
206
(field->page == field->form->curpage))
207
208
/* Logic to determine whether or not we are on the first position in the
209
current field */
210
#define First_Position_In_Current_Field(form) \
211
(((form)->currow==0) && ((form)->curcol==0))
212
213
214
#define Minimum(a,b) (((a)<=(b)) ? (a) : (b))
215
#define Maximum(a,b) (((a)>=(b)) ? (a) : (b))
216
217
/*---------------------------------------------------------------------------
218
| Facility : libnform
219
| Function : static char *Get_Start_Of_Data(char * buf, int blen)
220
|
221
| Description : Return pointer to first non-blank position in buffer.
222
| If buffer is empty return pointer to buffer itself.
223
|
224
| Return Values : Pointer to first non-blank position in buffer
225
+--------------------------------------------------------------------------*/
226
INLINE static char *Get_Start_Of_Data(char * buf, int blen)
227
{
228
char *p = buf;
229
char *end = &buf[blen];
230
231
assert(buf && blen>=0);
232
while( (p < end) && is_blank(*p) )
233
p++;
234
return( (p==end) ? buf : p );
235
}
236
237
/*---------------------------------------------------------------------------
238
| Facility : libnform
239
| Function : static char *After_End_Of_Data(char * buf, int blen)
240
|
241
| Description : Return pointer after last non-blank position in buffer.
242
| If buffer is empty, return pointer to buffer itself.
243
|
244
| Return Values : Pointer to position after last non-blank position in
245
| buffer.
246
+--------------------------------------------------------------------------*/
247
INLINE static char *After_End_Of_Data(char * buf,int blen)
248
{
249
char *p = &buf[blen];
250
251
assert(buf && blen>=0);
252
while( (p>buf) && is_blank(p[-1]) )
253
p--;
254
return( p );
255
}
256
257
/*---------------------------------------------------------------------------
258
| Facility : libnform
259
| Function : static char *Get_First_Whitespace_Character(
260
| char * buf, int blen)
261
|
262
| Description : Position to the first whitespace character.
263
|
264
| Return Values : Pointer to first whitespace character in buffer.
265
+--------------------------------------------------------------------------*/
266
INLINE static char *Get_First_Whitespace_Character(char * buf, int blen)
267
{
268
char *p = buf;
269
char *end = &p[blen];
270
271
assert(buf && blen>=0);
272
while( (p < end) && !is_blank(*p))
273
p++;
274
return( (p==end) ? buf : p );
275
}
276
277
/*---------------------------------------------------------------------------
278
| Facility : libnform
279
| Function : static char *After_Last_Whitespace_Character(
280
| char * buf, int blen)
281
|
282
| Description : Get the position after the last whitespace character.
283
|
284
| Return Values : Pointer to position after last whitespace character in
285
| buffer.
286
+--------------------------------------------------------------------------*/
287
INLINE static char *After_Last_Whitespace_Character(char * buf, int blen)
288
{
289
char *p = &buf[blen];
290
291
assert(buf && blen>=0);
292
while( (p>buf) && !is_blank(p[-1]) )
293
p--;
294
return( p );
295
}
296
297
/* Set this to 1 to use the div_t version. This is a good idea if your
298
compiler has an intrinsic div() support. Unfortunately GNU-C has it
299
not yet.
300
N.B.: This only works if form->curcol follows immediately form->currow
301
and both are of type int.
302
*/
303
#define USE_DIV_T (0)
304
305
/*---------------------------------------------------------------------------
306
| Facility : libnform
307
| Function : static void Adjust_Cursor_Position(
308
| FORM * form, const char * pos)
309
|
310
| Description : Set current row and column of the form to values
311
| corresponding to the buffer position.
312
|
313
| Return Values : -
314
+--------------------------------------------------------------------------*/
315
INLINE static void Adjust_Cursor_Position(FORM * form, const char * pos)
316
{
317
FIELD *field;
318
int idx;
319
320
field = form->current;
321
assert( pos >= field->buf && field->dcols > 0);
322
idx = (int)( pos - field->buf );
323
#if USE_DIV_T
324
*((div_t *)&(form->currow)) = div(idx,field->dcols);
325
#else
326
form->currow = idx / field->dcols;
327
form->curcol = idx - field->cols * form->currow;
328
#endif
329
if ( field->drows < form->currow )
330
form->currow = 0;
331
}
332
333
/*---------------------------------------------------------------------------
334
| Facility : libnform
335
| Function : static void Buffer_To_Window(
336
| const FIELD * field,
337
| WINDOW * win)
338
|
339
| Description : Copy the buffer to the window. If its a multiline
340
| field, the buffer is split to the lines of the
341
| window without any editing.
342
|
343
| Return Values : -
344
+--------------------------------------------------------------------------*/
345
static void Buffer_To_Window(const FIELD * field, WINDOW * win)
346
{
347
int width, height;
348
int len;
349
int row;
350
char *pBuffer;
351
352
assert(win && field);
353
354
getmaxyx(win, height, width);
355
356
for(row=0, pBuffer=field->buf;
357
row < height;
358
row++, pBuffer += width )
359
{
360
if ((len = (int)( After_End_Of_Data( pBuffer, width ) - pBuffer )) > 0)
361
{
362
wmove( win, row, 0 );
363
waddnstr( win, pBuffer, len );
364
}
365
}
366
}
367
368
/*---------------------------------------------------------------------------
369
| Facility : libnform
370
| Function : static void Window_To_Buffer(
371
| WINDOW * win,
372
| FIELD * field)
373
|
374
| Description : Copy the content of the window into the buffer.
375
| The multiple lines of a window are simply
376
| concatenated into the buffer. Pad characters in
377
| the window will be replaced by blanks in the buffer.
378
|
379
| Return Values : -
380
+--------------------------------------------------------------------------*/
381
static void Window_To_Buffer(WINDOW * win, FIELD * field)
382
{
383
int pad;
384
int len = 0;
385
char *p;
386
int row, height, width;
387
388
assert(win && field && field->buf );
389
390
pad = field->pad;
391
p = field->buf;
392
getmaxyx(win, height, width);
393
394
for(row=0; (row < height) && (row < field->drows); row++ )
395
{
396
wmove( win, row, 0 );
397
len += winnstr( win, p+len, field->dcols );
398
}
399
p[len] = '\0';
400
401
/* replace visual padding character by blanks in buffer */
402
if (pad != C_BLANK)
403
{
404
int i;
405
for(i=0; i<len; i++, p++)
406
{
407
if (*p==pad)
408
*p = C_BLANK;
409
}
410
}
411
}
412
413
/*---------------------------------------------------------------------------
414
| Facility : libnform
415
| Function : static void Synchronize_Buffer(FORM * form)
416
|
417
| Description : If there was a change, copy the content of the
418
| window into the buffer, so the buffer is synchronized
419
| with the windows content. We have to indicate that the
420
| buffer needs validation due to the change.
421
|
422
| Return Values : -
423
+--------------------------------------------------------------------------*/
424
INLINE static void Synchronize_Buffer(FORM * form)
425
{
426
if (form->status & _WINDOW_MODIFIED)
427
{
428
form->status &= ~_WINDOW_MODIFIED;
429
form->status |= _FCHECK_REQUIRED;
430
Window_To_Buffer(form->w,form->current);
431
wmove(form->w,form->currow,form->curcol);
432
}
433
}
434
435
/*---------------------------------------------------------------------------
436
| Facility : libnform
437
| Function : static bool Field_Grown( FIELD *field, int amount)
438
|
439
| Description : This function is called for growable dynamic fields
440
| only. It has to increase the buffers and to allocate
441
| a new window for this field.
442
| This function has the side effect to set a new
443
| field-buffer pointer, the dcols and drows values
444
| as well as a new current Window for the field.
445
|
446
| Return Values : TRUE - field successfully increased
447
| FALSE - there was some error
448
+--------------------------------------------------------------------------*/
449
static bool Field_Grown(FIELD * field, int amount)
450
{
451
bool result = FALSE;
452
453
if (field && Growable(field))
454
{
455
bool single_line_field = Single_Line_Field(field);
456
int old_buflen = Buffer_Length(field);
457
int new_buflen;
458
int old_dcols = field->dcols;
459
int old_drows = field->drows;
460
char *oldbuf = field->buf;
461
char *newbuf;
462
463
int growth;
464
FORM *form = field->form;
465
bool need_visual_update = ((form != (FORM *)0) &&
466
(form->status & _POSTED) &&
467
(form->current==field));
468
469
if (need_visual_update)
470
Synchronize_Buffer(form);
471
472
if (single_line_field)
473
{
474
growth = field->cols * amount;
475
if (field->maxgrow)
476
growth = Minimum(field->maxgrow - field->dcols,growth);
477
field->dcols += growth;
478
if (field->dcols == field->maxgrow)
479
field->status &= ~_MAY_GROW;
480
}
481
else
482
{
483
growth = (field->rows + field->nrow) * amount;
484
if (field->maxgrow)
485
growth = Minimum(field->maxgrow - field->drows,growth);
486
field->drows += growth;
487
if (field->drows == field->maxgrow)
488
field->status &= ~_MAY_GROW;
489
}
490
/* drows, dcols changed, so we get really the new buffer length */
491
new_buflen = Buffer_Length(field);
492
newbuf=(char *)malloc((size_t)Total_Buffer_Size(field));
493
if (!newbuf)
494
{ /* restore to previous state */
495
field->dcols = old_dcols;
496
field->drows = old_drows;
497
if (( single_line_field && (field->dcols!=field->maxgrow)) ||
498
(!single_line_field && (field->drows!=field->maxgrow)))
499
field->status |= _MAY_GROW;
500
return FALSE;
501
}
502
else
503
{ /* Copy all the buffers. This is the reason why we can't
504
just use realloc().
505
*/
506
int i;
507
char *old_bp;
508
char *new_bp;
509
510
field->buf = newbuf;
511
for(i=0;i<=field->nbuf;i++)
512
{
513
new_bp = Address_Of_Nth_Buffer(field,i);
514
old_bp = oldbuf + i*(1+old_buflen);
515
memcpy(new_bp,old_bp,(size_t)old_buflen);
516
if (new_buflen > old_buflen)
517
memset(new_bp + old_buflen,C_BLANK,
518
(size_t)(new_buflen - old_buflen));
519
*(new_bp + new_buflen) = '\0';
520
}
521
522
if (need_visual_update)
523
{
524
WINDOW *new_window = newpad(field->drows,field->dcols);
525
if (!new_window)
526
{ /* restore old state */
527
field->dcols = old_dcols;
528
field->drows = old_drows;
529
field->buf = oldbuf;
530
if (( single_line_field &&
531
(field->dcols!=field->maxgrow)) ||
532
(!single_line_field &&
533
(field->drows!=field->maxgrow)))
534
field->status |= _MAY_GROW;
535
free( newbuf );
536
return FALSE;
537
}
538
assert(form!=(FORM *)0);
539
delwin(form->w);
540
form->w = new_window;
541
Set_Field_Window_Attributes(field,form->w);
542
werase(form->w);
543
Buffer_To_Window(field,form->w);
544
untouchwin(form->w);
545
wmove(form->w,form->currow,form->curcol);
546
}
547
548
free(oldbuf);
549
/* reflect changes in linked fields */
550
if (field != field->link)
551
{
552
FIELD *linked_field;
553
for(linked_field = field->link;
554
linked_field!= field;
555
linked_field = linked_field->link)
556
{
557
linked_field->buf = field->buf;
558
linked_field->drows = field->drows;
559
linked_field->dcols = field->dcols;
560
}
561
}
562
result = TRUE;
563
}
564
}
565
return(result);
566
}
567
568
/*---------------------------------------------------------------------------
569
| Facility : libnform
570
| Function : int _nc_Position_Form_Cursor(FORM * form)
571
|
572
| Description : Position the cursor in the window for the current
573
| field to be in sync. with the currow and curcol
574
| values.
575
|
576
| Return Values : E_OK - success
577
| E_BAD_ARGUMENT - invalid form pointer
578
| E_SYSTEM_ERROR - form has no current field or
579
| field-window
580
+--------------------------------------------------------------------------*/
581
int
582
_nc_Position_Form_Cursor(FORM * form)
583
{
584
FIELD *field;
585
WINDOW *formwin;
586
587
if (!form)
588
return(E_BAD_ARGUMENT);
589
590
if (!form->w || !form->current)
591
return(E_SYSTEM_ERROR);
592
593
field = form->current;
594
formwin = Get_Form_Window(form);
595
596
wmove( form->w, form->currow, form->curcol );
597
if ( Has_Invisible_Parts(field) )
598
{
599
/* in this case fieldwin isn't derived from formwin, so we have
600
to move the cursor in formwin by hand... */
601
wmove(formwin,
602
field->frow + form->currow - form->toprow,
603
field->fcol + form->curcol - form->begincol);
604
wcursyncup(formwin);
605
}
606
else
607
wcursyncup(form->w);
608
return(E_OK);
609
}
610
611
/*---------------------------------------------------------------------------
612
| Facility : libnform
613
| Function : int _nc_Refresh_Current_Field(FORM * form)
614
|
615
| Description : Propagate the changes in the fields window to the
616
| window of the form.
617
|
618
| Return Values : E_OK - on success
619
| E_BAD_ARGUMENT - invalid form pointer
620
| E_SYSTEM_ERROR - general error
621
+--------------------------------------------------------------------------*/
622
int
623
_nc_Refresh_Current_Field(FORM * form)
624
{
625
WINDOW *formwin;
626
FIELD *field;
627
628
if (!form)
629
RETURN(E_BAD_ARGUMENT);
630
631
if (!form->w || !form->current)
632
RETURN(E_SYSTEM_ERROR);
633
634
field = form->current;
635
formwin = Get_Form_Window(form);
636
637
if (field->opts & O_PUBLIC)
638
{
639
if (Is_Scroll_Field(field))
640
{
641
/* Again, in this case the fieldwin isn't derived from formwin,
642
so we have to perform a copy operation. */
643
if (Single_Line_Field(field))
644
{ /* horizontal scrolling */
645
if (form->curcol < form->begincol)
646
form->begincol = form->curcol;
647
else
648
{
649
if (form->curcol >= (form->begincol + field->cols))
650
form->begincol = form->curcol - field->cols + 1;
651
}
652
copywin(form->w,
653
formwin,
654
0,
655
form->begincol,
656
field->frow,
657
field->fcol,
658
field->frow,
659
field->cols + field->fcol - 1,
660
0);
661
}
662
else
663
{ /* A multiline, i.e. vertical scrolling field */
664
int row_after_bottom,first_modified_row,first_unmodified_row;
665
666
if (field->drows > field->rows)
667
{
668
row_after_bottom = form->toprow + field->rows;
669
if (form->currow < form->toprow)
670
{
671
form->toprow = form->currow;
672
field->status |= _NEWTOP;
673
}
674
if (form->currow >= row_after_bottom)
675
{
676
form->toprow = form->currow - field->rows + 1;
677
field->status |= _NEWTOP;
678
}
679
if (field->status & _NEWTOP)
680
{ /* means we have to copy whole range */
681
first_modified_row = form->toprow;
682
first_unmodified_row = first_modified_row + field->rows;
683
field->status &= ~_NEWTOP;
684
}
685
else
686
{ /* we try to optimize : finding the range of touched
687
lines */
688
first_modified_row = form->toprow;
689
while(first_modified_row < row_after_bottom)
690
{
691
if (is_linetouched(form->w,first_modified_row))
692
break;
693
first_modified_row++;
694
}
695
first_unmodified_row = first_modified_row;
696
while(first_unmodified_row < row_after_bottom)
697
{
698
if (!is_linetouched(form->w,first_unmodified_row))
699
break;
700
first_unmodified_row++;
701
}
702
}
703
}
704
else
705
{
706
first_modified_row = form->toprow;
707
first_unmodified_row = first_modified_row + field->rows;
708
}
709
if (first_unmodified_row != first_modified_row)
710
copywin(form->w,
711
formwin,
712
first_modified_row,
713
0,
714
field->frow + first_modified_row - form->toprow,
715
field->fcol,
716
field->frow + first_unmodified_row - form->toprow - 1,
717
field->cols + field->fcol - 1,
718
0);
719
}
720
wsyncup(formwin);
721
}
722
else
723
{ /* if the field-window is simply a derived window, i.e. contains
724
no invisible parts, the whole thing is trivial
725
*/
726
wsyncup(form->w);
727
}
728
}
729
untouchwin(form->w);
730
return _nc_Position_Form_Cursor(form);
731
}
732
733
/*---------------------------------------------------------------------------
734
| Facility : libnform
735
| Function : static void Perform_Justification(
736
| FIELD * field,
737
| WINDOW * win)
738
|
739
| Description : Output field with requested justification
740
|
741
| Return Values : -
742
+--------------------------------------------------------------------------*/
743
static void Perform_Justification(FIELD * field, WINDOW * win)
744
{
745
char *bp;
746
int len;
747
int col = 0;
748
749
bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
750
len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field)) - bp);
751
752
if (len>0)
753
{
754
assert(win && (field->drows == 1) && (field->dcols == field->cols));
755
756
switch(field->just)
757
{
758
case JUSTIFY_LEFT:
759
break;
760
case JUSTIFY_CENTER:
761
col = (field->cols - len)/2;
762
break;
763
case JUSTIFY_RIGHT:
764
col = field->cols - len;
765
break;
766
default:
767
break;
768
}
769
770
wmove(win,0,col);
771
waddnstr(win,bp,len);
772
}
773
}
774
775
/*---------------------------------------------------------------------------
776
| Facility : libnform
777
| Function : static void Undo_Justification(
778
| FIELD * field,
779
| WINDOW * win)
780
|
781
| Description : Display field without any justification, i.e.
782
| left justified
783
|
784
| Return Values : -
785
+--------------------------------------------------------------------------*/
786
static void Undo_Justification(FIELD * field, WINDOW * win)
787
{
788
char *bp;
789
int len;
790
791
bp = Get_Start_Of_Data(field->buf,Buffer_Length(field));
792
len = (int)(After_End_Of_Data(field->buf,Buffer_Length(field))-bp);
793
794
if (len>0)
795
{
796
assert(win != 0);
797
wmove(win,0,0);
798
waddnstr(win,bp,len);
799
}
800
}
801
802
/*---------------------------------------------------------------------------
803
| Facility : libnform
804
| Function : static bool Check_Char(
805
| FIELDTYPE * typ,
806
| int ch,
807
| TypeArgument *argp)
808
|
809
| Description : Perform a single character check for character ch
810
| according to the fieldtype instance.
811
|
812
| Return Values : TRUE - Character is valid
813
| FALSE - Character is invalid
814
+--------------------------------------------------------------------------*/
815
static bool Check_Char(FIELDTYPE * typ, int ch, TypeArgument *argp)
816
{
817
if (typ)
818
{
819
if (typ->status & _LINKED_TYPE)
820
{
821
assert(argp != 0);
822
return(
823
Check_Char(typ->left ,ch,argp->left ) ||
824
Check_Char(typ->right,ch,argp->right) );
825
}
826
else
827
{
828
if (typ->ccheck)
829
return typ->ccheck(ch,(void *)argp);
830
}
831
}
832
return (isprint((unsigned char)ch) ? TRUE : FALSE);
833
}
834
835
/*---------------------------------------------------------------------------
836
| Facility : libnform
837
| Function : static int Display_Or_Erase_Field(
838
| FIELD * field,
839
| bool bEraseFlag)
840
|
841
| Description : Create a subwindow for the field and display the
842
| buffer contents (apply justification if required)
843
| or simply erase the field.
844
|
845
| Return Values : E_OK - on success
846
| E_SYSTEM_ERROR - some error (typical no memory)
847
+--------------------------------------------------------------------------*/
848
static int Display_Or_Erase_Field(FIELD * field, bool bEraseFlag)
849
{
850
WINDOW *win;
851
WINDOW *fwin;
852
853
if (!field)
854
return E_SYSTEM_ERROR;
855
856
fwin = Get_Form_Window(field->form);
857
win = derwin(fwin,
858
field->rows,field->cols,field->frow,field->fcol);
859
860
if (!win)
861
return E_SYSTEM_ERROR;
862
else
863
{
864
if (field->opts & O_VISIBLE)
865
Set_Field_Window_Attributes(field,win);
866
else
867
{
868
#if defined(__LSB_VERSION__)
869
/* getattrs() would be handy, but it is not part of LSB 4.0 */
870
attr_t fwinAttrs;
871
short fwinPair;
872
wattr_get(fwin, &fwinAttrs, &fwinPair, 0);
873
wattr_set(win, fwinAttrs, fwinPair, 0);
874
#else
875
wattrset(win,getattrs(fwin));
876
#endif
877
}
878
werase(win);
879
}
880
881
if (!bEraseFlag)
882
{
883
if (field->opts & O_PUBLIC)
884
{
885
if (Justification_Allowed(field))
886
Perform_Justification(field,win);
887
else
888
Buffer_To_Window(field,win);
889
}
890
field->status &= ~_NEWTOP;
891
}
892
wsyncup(win);
893
delwin(win);
894
return E_OK;
895
}
896
897
/* Macros to preset the bEraseFlag */
898
#define Display_Field(field) Display_Or_Erase_Field(field,FALSE)
899
#define Erase_Field(field) Display_Or_Erase_Field(field,TRUE)
900
901
/*---------------------------------------------------------------------------
902
| Facility : libnform
903
| Function : static int Synchronize_Field(FIELD * field)
904
|
905
| Description : Synchronize the windows content with the value in
906
| the buffer.
907
|
908
| Return Values : E_OK - success
909
| E_BAD_ARGUMENT - invalid field pointer
910
| E_SYSTEM_ERROR - some severe basic error
911
+--------------------------------------------------------------------------*/
912
static int Synchronize_Field(FIELD * field)
913
{
914
FORM *form;
915
int res = E_OK;
916
917
if (!field)
918
return(E_BAD_ARGUMENT);
919
920
if (((form=field->form) != (FORM *)0)
921
&& Field_Really_Appears(field))
922
{
923
if (field == form->current)
924
{
925
form->currow = form->curcol = form->toprow = form->begincol = 0;
926
werase(form->w);
927
928
if ( (field->opts & O_PUBLIC) && Justification_Allowed(field) )
929
Undo_Justification( field, form->w );
930
else
931
Buffer_To_Window( field, form->w );
932
933
field->status |= _NEWTOP;
934
res = _nc_Refresh_Current_Field( form );
935
}
936
else
937
res = Display_Field( field );
938
}
939
field->status |= _CHANGED;
940
return(res);
941
}
942
943
/*---------------------------------------------------------------------------
944
| Facility : libnform
945
| Function : static int Synchronize_Linked_Fields(FIELD * field)
946
|
947
| Description : Propagate the Synchronize_Field function to all linked
948
| fields. The first error that occurs in the sequence
949
| of updates is the returnvalue.
950
|
951
| Return Values : E_OK - success
952
| E_BAD_ARGUMENT - invalid field pointer
953
| E_SYSTEM_ERROR - some severe basic error
954
+--------------------------------------------------------------------------*/
955
static int Synchronize_Linked_Fields(FIELD * field)
956
{
957
FIELD *linked_field;
958
int res = E_OK;
959
int syncres;
960
961
if (!field)
962
return(E_BAD_ARGUMENT);
963
964
if (!field->link)
965
return(E_SYSTEM_ERROR);
966
967
for(linked_field = field->link;
968
linked_field!= field;
969
linked_field = linked_field->link )
970
{
971
if (((syncres=Synchronize_Field(linked_field)) != E_OK) &&
972
(res==E_OK))
973
res = syncres;
974
}
975
return(res);
976
}
977
978
/*---------------------------------------------------------------------------
979
| Facility : libnform
980
| Function : int _nc_Synchronize_Attributes(FIELD * field)
981
|
982
| Description : If a fields visual attributes have changed, this
983
| routine is called to propagate those changes to the
984
| screen.
985
|
986
| Return Values : E_OK - success
987
| E_BAD_ARGUMENT - invalid field pointer
988
| E_SYSTEM_ERROR - some severe basic error
989
+--------------------------------------------------------------------------*/
990
int _nc_Synchronize_Attributes(FIELD * field)
991
{
992
FORM *form;
993
int res = E_OK;
994
WINDOW *formwin;
995
996
if (!field)
997
return(E_BAD_ARGUMENT);
998
999
if (((form=field->form) != (FORM *)0)
1000
&& Field_Really_Appears(field))
1001
{
1002
if (form->current==field)
1003
{
1004
Synchronize_Buffer(form);
1005
Set_Field_Window_Attributes(field,form->w);
1006
werase(form->w);
1007
if (field->opts & O_PUBLIC)
1008
{
1009
if (Justification_Allowed(field))
1010
Undo_Justification(field,form->w);
1011
else
1012
Buffer_To_Window(field,form->w);
1013
}
1014
else
1015
{
1016
formwin = Get_Form_Window(form);
1017
copywin(form->w,formwin,
1018
0,0,
1019
field->frow,field->fcol,
1020
field->rows-1,field->cols-1,0);
1021
wsyncup(formwin);
1022
Buffer_To_Window(field,form->w);
1023
field->status |= _NEWTOP; /* fake refresh to paint all */
1024
_nc_Refresh_Current_Field(form);
1025
}
1026
}
1027
else
1028
{
1029
res = Display_Field(field);
1030
}
1031
}
1032
return(res);
1033
}
1034
1035
/*---------------------------------------------------------------------------
1036
| Facility : libnform
1037
| Function : int _nc_Synchronize_Options(FIELD * field,
1038
| Field_Options newopts)
1039
|
1040
| Description : If a fields options have changed, this routine is
1041
| called to propagate these changes to the screen and
1042
| to really change the behaviour of the field.
1043
|
1044
| Return Values : E_OK - success
1045
| E_BAD_ARGUMENT - invalid field pointer
1046
| E_SYSTEM_ERROR - some severe basic error
1047
+--------------------------------------------------------------------------*/
1048
int
1049
_nc_Synchronize_Options(FIELD *field, Field_Options newopts)
1050
{
1051
Field_Options oldopts;
1052
Field_Options changed_opts;
1053
FORM *form;
1054
int res = E_OK;
1055
1056
if (!field)
1057
return(E_BAD_ARGUMENT);
1058
1059
oldopts = field->opts;
1060
changed_opts = oldopts ^ newopts;
1061
field->opts = newopts;
1062
form = field->form;
1063
1064
if (form)
1065
{
1066
if (form->current == field)
1067
{
1068
field->opts = oldopts;
1069
return(E_CURRENT);
1070
}
1071
1072
if (form->status & _POSTED)
1073
{
1074
if (form->curpage == field->page)
1075
{
1076
if (changed_opts & O_VISIBLE)
1077
{
1078
if (newopts & O_VISIBLE)
1079
res = Display_Field(field);
1080
else
1081
res = Erase_Field(field);
1082
}
1083
else
1084
{
1085
if ((changed_opts & O_PUBLIC) &&
1086
(newopts & O_VISIBLE))
1087
res = Display_Field(field);
1088
}
1089
}
1090
}
1091
}
1092
1093
if (changed_opts & O_STATIC)
1094
{
1095
bool single_line_field = Single_Line_Field(field);
1096
int res2 = E_OK;
1097
1098
if (newopts & O_STATIC)
1099
{ /* the field becomes now static */
1100
field->status &= ~_MAY_GROW;
1101
/* if actually we have no hidden columns, justification may
1102
occur again */
1103
if (single_line_field &&
1104
(field->cols == field->dcols) &&
1105
(field->just != NO_JUSTIFICATION) &&
1106
Field_Really_Appears(field))
1107
{
1108
res2 = Display_Field(field);
1109
}
1110
}
1111
else
1112
{ /* field is no longer static */
1113
if ((field->maxgrow==0) ||
1114
( single_line_field && (field->dcols < field->maxgrow)) ||
1115
(!single_line_field && (field->drows < field->maxgrow)))
1116
{
1117
field->status |= _MAY_GROW;
1118
/* a field with justification now changes its behaviour,
1119
so we must redisplay it */
1120
if (single_line_field &&
1121
(field->just != NO_JUSTIFICATION) &&
1122
Field_Really_Appears(field))
1123
{
1124
res2 = Display_Field(field);
1125
}
1126
}
1127
}
1128
if (res2 != E_OK)
1129
res = res2;
1130
}
1131
1132
return(res);
1133
}
1134
1135
/*---------------------------------------------------------------------------
1136
| Facility : libnform
1137
| Function : int _nc_Set_Current_Field(FORM * form,
1138
| FIELD * newfield)
1139
|
1140
| Description : Make the newfield the new current field.
1141
|
1142
| Return Values : E_OK - success
1143
| E_BAD_ARGUMENT - invalid form or field pointer
1144
| E_SYSTEM_ERROR - some severe basic error
1145
+--------------------------------------------------------------------------*/
1146
int
1147
_nc_Set_Current_Field(FORM *form, FIELD *newfield)
1148
{
1149
FIELD *field;
1150
WINDOW *new_window;
1151
1152
if (!form || !newfield || !form->current || (newfield->form!=form))
1153
return(E_BAD_ARGUMENT);
1154
1155
if ( (form->status & _IN_DRIVER) )
1156
return(E_BAD_STATE);
1157
1158
if (!(form->field))
1159
return(E_NOT_CONNECTED);
1160
1161
field = form->current;
1162
1163
if ((field!=newfield) ||
1164
!(form->status & _POSTED))
1165
{
1166
if ((form->w) &&
1167
(field->opts & O_VISIBLE) &&
1168
(field->form->curpage == field->page))
1169
{
1170
_nc_Refresh_Current_Field(form);
1171
if (field->opts & O_PUBLIC)
1172
{
1173
if (field->drows > field->rows)
1174
{
1175
if (form->toprow==0)
1176
field->status &= ~_NEWTOP;
1177
else
1178
field->status |= _NEWTOP;
1179
}
1180
else
1181
{
1182
if (Justification_Allowed(field))
1183
{
1184
Window_To_Buffer(form->w,field);
1185
werase(form->w);
1186
Perform_Justification(field,form->w);
1187
wsyncup(form->w);
1188
}
1189
}
1190
}
1191
delwin(form->w);
1192
}
1193
1194
field = newfield;
1195
1196
if (Has_Invisible_Parts(field))
1197
new_window = newpad(field->drows,field->dcols);
1198
else
1199
new_window = derwin(Get_Form_Window(form),
1200
field->rows,field->cols,field->frow,field->fcol);
1201
1202
if (!new_window)
1203
return(E_SYSTEM_ERROR);
1204
1205
form->current = field;
1206
form->w = new_window;
1207
form->status &= ~_WINDOW_MODIFIED;
1208
Set_Field_Window_Attributes(field,form->w);
1209
1210
if (Has_Invisible_Parts(field))
1211
{
1212
werase(form->w);
1213
Buffer_To_Window(field,form->w);
1214
}
1215
else
1216
{
1217
if (Justification_Allowed(field))
1218
{
1219
werase(form->w);
1220
Undo_Justification(field,form->w);
1221
wsyncup(form->w);
1222
}
1223
}
1224
1225
untouchwin(form->w);
1226
}
1227
1228
form->currow = form->curcol = form->toprow = form->begincol = 0;
1229
return(E_OK);
1230
}
1231
1232
/*----------------------------------------------------------------------------
1233
Intra-Field Navigation routines
1234
--------------------------------------------------------------------------*/
1235
1236
/*---------------------------------------------------------------------------
1237
| Facility : libnform
1238
| Function : static int IFN_Next_Character(FORM * form)
1239
|
1240
| Description : Move to the next character in the field. In a multiline
1241
| field this wraps at the end of the line.
1242
|
1243
| Return Values : E_OK - success
1244
| E_REQUEST_DENIED - at the rightmost position
1245
+--------------------------------------------------------------------------*/
1246
static int IFN_Next_Character(FORM * form)
1247
{
1248
FIELD *field = form->current;
1249
1250
if ((++(form->curcol))==field->dcols)
1251
{
1252
if ((++(form->currow))==field->drows)
1253
{
1254
#if GROW_IF_NAVIGATE
1255
if (!Single_Line_Field(field) && Field_Grown(field,1)) {
1256
form->curcol = 0;
1257
return(E_OK);
1258
}
1259
#endif
1260
form->currow--;
1261
#if GROW_IF_NAVIGATE
1262
if (Single_Line_Field(field) && Field_Grown(field,1))
1263
return(E_OK);
1264
#endif
1265
form->curcol--;
1266
return(E_REQUEST_DENIED);
1267
}
1268
form->curcol = 0;
1269
}
1270
return(E_OK);
1271
}
1272
1273
/*---------------------------------------------------------------------------
1274
| Facility : libnform
1275
| Function : static int IFN_Previous_Character(FORM * form)
1276
|
1277
| Description : Move to the previous character in the field. In a
1278
| multiline field this wraps and the beginning of the
1279
| line.
1280
|
1281
| Return Values : E_OK - success
1282
| E_REQUEST_DENIED - at the leftmost position
1283
+--------------------------------------------------------------------------*/
1284
static int IFN_Previous_Character(FORM * form)
1285
{
1286
if ((--(form->curcol))<0)
1287
{
1288
if ((--(form->currow))<0)
1289
{
1290
form->currow++;
1291
form->curcol++;
1292
return(E_REQUEST_DENIED);
1293
}
1294
form->curcol = form->current->dcols - 1;
1295
}
1296
return(E_OK);
1297
}
1298
1299
/*---------------------------------------------------------------------------
1300
| Facility : libnform
1301
| Function : static int IFN_Next_Line(FORM * form)
1302
|
1303
| Description : Move to the beginning of the next line in the field
1304
|
1305
| Return Values : E_OK - success
1306
| E_REQUEST_DENIED - at the last line
1307
+--------------------------------------------------------------------------*/
1308
static int IFN_Next_Line(FORM * form)
1309
{
1310
FIELD *field = form->current;
1311
1312
if ((++(form->currow))==field->drows)
1313
{
1314
#if GROW_IF_NAVIGATE
1315
if (!Single_Line_Field(field) && Field_Grown(field,1))
1316
return(E_OK);
1317
#endif
1318
form->currow--;
1319
return(E_REQUEST_DENIED);
1320
}
1321
form->curcol = 0;
1322
return(E_OK);
1323
}
1324
1325
/*---------------------------------------------------------------------------
1326
| Facility : libnform
1327
| Function : static int IFN_Previous_Line(FORM * form)
1328
|
1329
| Description : Move to the beginning of the previous line in the field
1330
|
1331
| Return Values : E_OK - success
1332
| E_REQUEST_DENIED - at the first line
1333
+--------------------------------------------------------------------------*/
1334
static int IFN_Previous_Line(FORM * form)
1335
{
1336
if ( (--(form->currow)) < 0 )
1337
{
1338
form->currow++;
1339
return(E_REQUEST_DENIED);
1340
}
1341
form->curcol = 0;
1342
return(E_OK);
1343
}
1344
1345
/*---------------------------------------------------------------------------
1346
| Facility : libnform
1347
| Function : static int IFN_Next_Word(FORM * form)
1348
|
1349
| Description : Move to the beginning of the next word in the field.
1350
|
1351
| Return Values : E_OK - success
1352
| E_REQUEST_DENIED - there is no next word
1353
+--------------------------------------------------------------------------*/
1354
static int IFN_Next_Word(FORM * form)
1355
{
1356
FIELD *field = form->current;
1357
char *bp = Address_Of_Current_Position_In_Buffer(form);
1358
char *s;
1359
char *t;
1360
1361
/* We really need access to the data, so we have to synchronize */
1362
Synchronize_Buffer(form);
1363
1364
/* Go to the first whitespace after the current position (including
1365
current position). This is then the startpoint to look for the
1366
next non-blank data */
1367
s = Get_First_Whitespace_Character(bp,Buffer_Length(field) -
1368
(int)(bp - field->buf));
1369
1370
/* Find the start of the next word */
1371
t = Get_Start_Of_Data(s,Buffer_Length(field) -
1372
(int)(s - field->buf));
1373
#if !FRIENDLY_PREV_NEXT_WORD
1374
if (s==t)
1375
return(E_REQUEST_DENIED);
1376
else
1377
#endif
1378
{
1379
Adjust_Cursor_Position(form,t);
1380
return(E_OK);
1381
}
1382
}
1383
1384
/*---------------------------------------------------------------------------
1385
| Facility : libnform
1386
| Function : static int IFN_Previous_Word(FORM * form)
1387
|
1388
| Description : Move to the beginning of the previous word in the field.
1389
|
1390
| Return Values : E_OK - success
1391
| E_REQUEST_DENIED - there is no previous word
1392
+--------------------------------------------------------------------------*/
1393
static int IFN_Previous_Word(FORM * form)
1394
{
1395
FIELD *field = form->current;
1396
char *bp = Address_Of_Current_Position_In_Buffer(form);
1397
char *s;
1398
char *t;
1399
bool again = FALSE;
1400
1401
/* We really need access to the data, so we have to synchronize */
1402
Synchronize_Buffer(form);
1403
1404
s = After_End_Of_Data(field->buf,(int)(bp-field->buf));
1405
/* s points now right after the last non-blank in the buffer before bp.
1406
If bp was in a word, s equals bp. In this case we must find the last
1407
whitespace in the buffer before bp and repeat the game to really find
1408
the previous word! */
1409
if (s==bp)
1410
again = TRUE;
1411
1412
/* And next call now goes backward to look for the last whitespace
1413
before that, pointing right after this, so it points to the begin
1414
of the previous word.
1415
*/
1416
t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1417
#if !FRIENDLY_PREV_NEXT_WORD
1418
if (s==t)
1419
return(E_REQUEST_DENIED);
1420
#endif
1421
if (again)
1422
{ /* and do it again, replacing bp by t */
1423
s = After_End_Of_Data(field->buf,(int)(t - field->buf));
1424
t = After_Last_Whitespace_Character(field->buf,(int)(s - field->buf));
1425
#if !FRIENDLY_PREV_NEXT_WORD
1426
if (s==t)
1427
return(E_REQUEST_DENIED);
1428
#endif
1429
}
1430
Adjust_Cursor_Position(form,t);
1431
return(E_OK);
1432
}
1433
1434
/*---------------------------------------------------------------------------
1435
| Facility : libnform
1436
| Function : static int IFN_Beginning_Of_Field(FORM * form)
1437
|
1438
| Description : Place the cursor at the first non-pad character in
1439
| the field.
1440
|
1441
| Return Values : E_OK - success
1442
+--------------------------------------------------------------------------*/
1443
static int IFN_Beginning_Of_Field(FORM * form)
1444
{
1445
FIELD *field = form->current;
1446
1447
Synchronize_Buffer(form);
1448
Adjust_Cursor_Position(form,
1449
Get_Start_Of_Data(field->buf,Buffer_Length(field)));
1450
return(E_OK);
1451
}
1452
1453
/*---------------------------------------------------------------------------
1454
| Facility : libnform
1455
| Function : static int IFN_End_Of_Field(FORM * form)
1456
|
1457
| Description : Place the cursor after the last non-pad character in
1458
| the field. If the field occupies the last position in
1459
| the buffer, the cursor is positioned on the last
1460
| character.
1461
|
1462
| Return Values : E_OK - success
1463
+--------------------------------------------------------------------------*/
1464
static int IFN_End_Of_Field(FORM * form)
1465
{
1466
FIELD *field = form->current;
1467
char *pos;
1468
1469
Synchronize_Buffer(form);
1470
pos = After_End_Of_Data(field->buf,Buffer_Length(field));
1471
if (pos==(field->buf + Buffer_Length(field)))
1472
pos--;
1473
Adjust_Cursor_Position(form,pos);
1474
return(E_OK);
1475
}
1476
1477
/*---------------------------------------------------------------------------
1478
| Facility : libnform
1479
| Function : static int IFN_Beginning_Of_Line(FORM * form)
1480
|
1481
| Description : Place the cursor on the first non-pad character in
1482
| the current line of the field.
1483
|
1484
| Return Values : E_OK - success
1485
+--------------------------------------------------------------------------*/
1486
static int IFN_Beginning_Of_Line(FORM * form)
1487
{
1488
FIELD *field = form->current;
1489
1490
Synchronize_Buffer(form);
1491
Adjust_Cursor_Position(form,
1492
Get_Start_Of_Data(Address_Of_Current_Row_In_Buffer(form),
1493
field->dcols));
1494
return(E_OK);
1495
}
1496
1497
/*---------------------------------------------------------------------------
1498
| Facility : libnform
1499
| Function : static int IFN_End_Of_Line(FORM * form)
1500
|
1501
| Description : Place the cursor after the last non-pad character in the
1502
| current line of the field. If the field occupies the
1503
| last column in the line, the cursor is positioned on the
1504
| last character of the line.
1505
|
1506
| Return Values : E_OK - success
1507
+--------------------------------------------------------------------------*/
1508
static int IFN_End_Of_Line(FORM * form)
1509
{
1510
FIELD *field = form->current;
1511
char *pos;
1512
char *bp;
1513
1514
Synchronize_Buffer(form);
1515
bp = Address_Of_Current_Row_In_Buffer(form);
1516
pos = After_End_Of_Data(bp,field->dcols);
1517
if (pos == (bp + field->dcols))
1518
pos--;
1519
Adjust_Cursor_Position(form,pos);
1520
return(E_OK);
1521
}
1522
1523
/*---------------------------------------------------------------------------
1524
| Facility : libnform
1525
| Function : static int IFN_Left_Character(FORM * form)
1526
|
1527
| Description : Move one character to the left in the current line.
1528
| This doesn't cycle.
1529
|
1530
| Return Values : E_OK - success
1531
| E_REQUEST_DENIED - already in first column
1532
+--------------------------------------------------------------------------*/
1533
static int IFN_Left_Character(FORM * form)
1534
{
1535
if ( (--(form->curcol)) < 0 )
1536
{
1537
form->curcol++;
1538
return(E_REQUEST_DENIED);
1539
}
1540
return(E_OK);
1541
}
1542
1543
/*---------------------------------------------------------------------------
1544
| Facility : libnform
1545
| Function : static int IFN_Right_Character(FORM * form)
1546
|
1547
| Description : Move one character to the right in the current line.
1548
| This doesn't cycle.
1549
|
1550
| Return Values : E_OK - success
1551
| E_REQUEST_DENIED - already in last column
1552
+--------------------------------------------------------------------------*/
1553
static int IFN_Right_Character(FORM * form)
1554
{
1555
if ( (++(form->curcol)) == form->current->dcols )
1556
{
1557
#if GROW_IF_NAVIGATE
1558
FIELD *field = form->current;
1559
if (Single_Line_Field(field) && Field_Grown(field,1))
1560
return(E_OK);
1561
#endif
1562
--(form->curcol);
1563
return(E_REQUEST_DENIED);
1564
}
1565
return(E_OK);
1566
}
1567
1568
/*---------------------------------------------------------------------------
1569
| Facility : libnform
1570
| Function : static int IFN_Up_Character(FORM * form)
1571
|
1572
| Description : Move one line up. This doesn't cycle through the lines
1573
| of the field.
1574
|
1575
| Return Values : E_OK - success
1576
| E_REQUEST_DENIED - already in last column
1577
+--------------------------------------------------------------------------*/
1578
static int IFN_Up_Character(FORM * form)
1579
{
1580
if ( (--(form->currow)) < 0 )
1581
{
1582
form->currow++;
1583
return(E_REQUEST_DENIED);
1584
}
1585
return(E_OK);
1586
}
1587
1588
/*---------------------------------------------------------------------------
1589
| Facility : libnform
1590
| Function : static int IFN_Down_Character(FORM * form)
1591
|
1592
| Description : Move one line down. This doesn't cycle through the
1593
| lines of the field.
1594
|
1595
| Return Values : E_OK - success
1596
| E_REQUEST_DENIED - already in last column
1597
+--------------------------------------------------------------------------*/
1598
static int IFN_Down_Character(FORM * form)
1599
{
1600
FIELD *field = form->current;
1601
1602
if ( (++(form->currow)) == field->drows )
1603
{
1604
#if GROW_IF_NAVIGATE
1605
if (!Single_Line_Field(field) && Field_Grown(field,1))
1606
return(E_OK);
1607
#endif
1608
--(form->currow);
1609
return(E_REQUEST_DENIED);
1610
}
1611
return(E_OK);
1612
}
1613
/*----------------------------------------------------------------------------
1614
END of Intra-Field Navigation routines
1615
--------------------------------------------------------------------------*/
1616
1617
/*----------------------------------------------------------------------------
1618
Vertical scrolling helper routines
1619
--------------------------------------------------------------------------*/
1620
1621
/*---------------------------------------------------------------------------
1622
| Facility : libnform
1623
| Function : static int VSC_Generic(FORM *form, int lines)
1624
|
1625
| Description : Scroll multi-line field forward (lines>0) or
1626
| backward (lines<0) this many lines.
1627
|
1628
| Return Values : E_OK - success
1629
| E_REQUEST_DENIED - can't scroll
1630
+--------------------------------------------------------------------------*/
1631
static int VSC_Generic(FORM *form, int lines)
1632
{
1633
FIELD *field = form->current;
1634
int res = E_REQUEST_DENIED;
1635
int rows_to_go = (lines > 0 ? lines : -lines);
1636
1637
if (lines > 0)
1638
{
1639
if ( (rows_to_go + form->toprow) > (field->drows - field->rows) )
1640
rows_to_go = (field->drows - field->rows - form->toprow);
1641
1642
if (rows_to_go > 0)
1643
{
1644
form->currow += rows_to_go;
1645
form->toprow += rows_to_go;
1646
res = E_OK;
1647
}
1648
}
1649
else
1650
{
1651
if (rows_to_go > form->toprow)
1652
rows_to_go = form->toprow;
1653
1654
if (rows_to_go > 0)
1655
{
1656
form->currow -= rows_to_go;
1657
form->toprow -= rows_to_go;
1658
res = E_OK;
1659
}
1660
}
1661
return(res);
1662
}
1663
/*----------------------------------------------------------------------------
1664
End of Vertical scrolling helper routines
1665
--------------------------------------------------------------------------*/
1666
1667
/*----------------------------------------------------------------------------
1668
Vertical scrolling routines
1669
--------------------------------------------------------------------------*/
1670
1671
/*---------------------------------------------------------------------------
1672
| Facility : libnform
1673
| Function : static int Vertical_Scrolling(
1674
| int (* const fct) (FORM *),
1675
| FORM * form)
1676
|
1677
| Description : Performs the generic vertical scrolling routines.
1678
| This has to check for a multi-line field and to set
1679
| the _NEWTOP flag if scrolling really occurred.
1680
|
1681
| Return Values : Propagated error code from low-level driver calls
1682
+--------------------------------------------------------------------------*/
1683
static int Vertical_Scrolling(int (* const fct) (FORM *), FORM * form)
1684
{
1685
int res = E_REQUEST_DENIED;
1686
1687
if (!Single_Line_Field(form->current))
1688
{
1689
res = fct(form);
1690
if (res == E_OK)
1691
form->current->status |= _NEWTOP;
1692
}
1693
return(res);
1694
}
1695
1696
/*---------------------------------------------------------------------------
1697
| Facility : libnform
1698
| Function : static int VSC_Scroll_Line_Forward(FORM * form)
1699
|
1700
| Description : Scroll multi-line field forward a line
1701
|
1702
| Return Values : E_OK - success
1703
| E_REQUEST_DENIED - no data ahead
1704
+--------------------------------------------------------------------------*/
1705
static int VSC_Scroll_Line_Forward(FORM * form)
1706
{
1707
return VSC_Generic(form,1);
1708
}
1709
1710
/*---------------------------------------------------------------------------
1711
| Facility : libnform
1712
| Function : static int VSC_Scroll_Line_Backward(FORM * form)
1713
|
1714
| Description : Scroll multi-line field backward a line
1715
|
1716
| Return Values : E_OK - success
1717
| E_REQUEST_DENIED - no data behind
1718
+--------------------------------------------------------------------------*/
1719
static int VSC_Scroll_Line_Backward(FORM * form)
1720
{
1721
return VSC_Generic(form,-1);
1722
}
1723
1724
/*---------------------------------------------------------------------------
1725
| Facility : libnform
1726
| Function : static int VSC_Scroll_Page_Forward(FORM * form)
1727
|
1728
| Description : Scroll a multi-line field forward a page
1729
|
1730
| Return Values : E_OK - success
1731
| E_REQUEST_DENIED - no data ahead
1732
+--------------------------------------------------------------------------*/
1733
static int VSC_Scroll_Page_Forward(FORM * form)
1734
{
1735
return VSC_Generic(form,form->current->rows);
1736
}
1737
1738
/*---------------------------------------------------------------------------
1739
| Facility : libnform
1740
| Function : static int VSC_Scroll_Half_Page_Forward(FORM * form)
1741
|
1742
| Description : Scroll a multi-line field forward half a page
1743
|
1744
| Return Values : E_OK - success
1745
| E_REQUEST_DENIED - no data ahead
1746
+--------------------------------------------------------------------------*/
1747
static int VSC_Scroll_Half_Page_Forward(FORM * form)
1748
{
1749
return VSC_Generic(form,(form->current->rows + 1)/2);
1750
}
1751
1752
/*---------------------------------------------------------------------------
1753
| Facility : libnform
1754
| Function : static int VSC_Scroll_Page_Backward(FORM * form)
1755
|
1756
| Description : Scroll a multi-line field backward a page
1757
|
1758
| Return Values : E_OK - success
1759
| E_REQUEST_DENIED - no data behind
1760
+--------------------------------------------------------------------------*/
1761
static int VSC_Scroll_Page_Backward(FORM * form)
1762
{
1763
return VSC_Generic(form, -(form->current->rows));
1764
}
1765
1766
/*---------------------------------------------------------------------------
1767
| Facility : libnform
1768
| Function : static int VSC_Scroll_Half_Page_Backward(FORM * form)
1769
|
1770
| Description : Scroll a multi-line field backward half a page
1771
|
1772
| Return Values : E_OK - success
1773
| E_REQUEST_DENIED - no data behind
1774
+--------------------------------------------------------------------------*/
1775
static int VSC_Scroll_Half_Page_Backward(FORM * form)
1776
{
1777
return VSC_Generic(form, -((form->current->rows + 1)/2));
1778
}
1779
/*----------------------------------------------------------------------------
1780
End of Vertical scrolling routines
1781
--------------------------------------------------------------------------*/
1782
1783
/*----------------------------------------------------------------------------
1784
Horizontal scrolling helper routines
1785
--------------------------------------------------------------------------*/
1786
1787
/*---------------------------------------------------------------------------
1788
| Facility : libnform
1789
| Function : static int HSC_Generic(FORM *form, int columns)
1790
|
1791
| Description : Scroll single-line field forward (columns>0) or
1792
| backward (columns<0) this many columns.
1793
|
1794
| Return Values : E_OK - success
1795
| E_REQUEST_DENIED - can't scroll
1796
+--------------------------------------------------------------------------*/
1797
static int HSC_Generic(FORM *form, int columns)
1798
{
1799
FIELD *field = form->current;
1800
int res = E_REQUEST_DENIED;
1801
int cols_to_go = (columns > 0 ? columns : -columns);
1802
1803
if (columns > 0)
1804
{
1805
if ((cols_to_go + form->begincol) > (field->dcols - field->cols))
1806
cols_to_go = field->dcols - field->cols - form->begincol;
1807
1808
if (cols_to_go > 0)
1809
{
1810
form->curcol += cols_to_go;
1811
form->begincol += cols_to_go;
1812
res = E_OK;
1813
}
1814
}
1815
else
1816
{
1817
if ( cols_to_go > form->begincol )
1818
cols_to_go = form->begincol;
1819
1820
if (cols_to_go > 0)
1821
{
1822
form->curcol -= cols_to_go;
1823
form->begincol -= cols_to_go;
1824
res = E_OK;
1825
}
1826
}
1827
return(res);
1828
}
1829
/*----------------------------------------------------------------------------
1830
End of Horizontal scrolling helper routines
1831
--------------------------------------------------------------------------*/
1832
1833
/*----------------------------------------------------------------------------
1834
Horizontal scrolling routines
1835
--------------------------------------------------------------------------*/
1836
1837
/*---------------------------------------------------------------------------
1838
| Facility : libnform
1839
| Function : static int Horizontal_Scrolling(
1840
| int (* const fct) (FORM *),
1841
| FORM * form)
1842
|
1843
| Description : Performs the generic horizontal scrolling routines.
1844
| This has to check for a single-line field.
1845
|
1846
| Return Values : Propagated error code from low-level driver calls
1847
+--------------------------------------------------------------------------*/
1848
static int Horizontal_Scrolling(int (* const fct) (FORM *), FORM * form)
1849
{
1850
if (Single_Line_Field(form->current))
1851
return fct(form);
1852
else
1853
return(E_REQUEST_DENIED);
1854
}
1855
1856
/*---------------------------------------------------------------------------
1857
| Facility : libnform
1858
| Function : static int HSC_Scroll_Char_Forward(FORM * form)
1859
|
1860
| Description : Scroll single-line field forward a character
1861
|
1862
| Return Values : E_OK - success
1863
| E_REQUEST_DENIED - no data ahead
1864
+--------------------------------------------------------------------------*/
1865
static int HSC_Scroll_Char_Forward(FORM *form)
1866
{
1867
return HSC_Generic(form,1);
1868
}
1869
1870
/*---------------------------------------------------------------------------
1871
| Facility : libnform
1872
| Function : static int HSC_Scroll_Char_Backward(FORM * form)
1873
|
1874
| Description : Scroll single-line field backward a character
1875
|
1876
| Return Values : E_OK - success
1877
| E_REQUEST_DENIED - no data behind
1878
+--------------------------------------------------------------------------*/
1879
static int HSC_Scroll_Char_Backward(FORM *form)
1880
{
1881
return HSC_Generic(form,-1);
1882
}
1883
1884
/*---------------------------------------------------------------------------
1885
| Facility : libnform
1886
| Function : static int HSC_Horizontal_Line_Forward(FORM* form)
1887
|
1888
| Description : Scroll single-line field forward a line
1889
|
1890
| Return Values : E_OK - success
1891
| E_REQUEST_DENIED - no data ahead
1892
+--------------------------------------------------------------------------*/
1893
static int HSC_Horizontal_Line_Forward(FORM * form)
1894
{
1895
return HSC_Generic(form,form->current->cols);
1896
}
1897
1898
/*---------------------------------------------------------------------------
1899
| Facility : libnform
1900
| Function : static int HSC_Horizontal_Half_Line_Forward(FORM* form)
1901
|
1902
| Description : Scroll single-line field forward half a line
1903
|
1904
| Return Values : E_OK - success
1905
| E_REQUEST_DENIED - no data ahead
1906
+--------------------------------------------------------------------------*/
1907
static int HSC_Horizontal_Half_Line_Forward(FORM * form)
1908
{
1909
return HSC_Generic(form,(form->current->cols + 1)/2);
1910
}
1911
1912
/*---------------------------------------------------------------------------
1913
| Facility : libnform
1914
| Function : static int HSC_Horizontal_Line_Backward(FORM* form)
1915
|
1916
| Description : Scroll single-line field backward a line
1917
|
1918
| Return Values : E_OK - success
1919
| E_REQUEST_DENIED - no data behind
1920
+--------------------------------------------------------------------------*/
1921
static int HSC_Horizontal_Line_Backward(FORM * form)
1922
{
1923
return HSC_Generic(form,-(form->current->cols));
1924
}
1925
1926
/*---------------------------------------------------------------------------
1927
| Facility : libnform
1928
| Function : static int HSC_Horizontal_Half_Line_Backward(FORM* form)
1929
|
1930
| Description : Scroll single-line field backward half a line
1931
|
1932
| Return Values : E_OK - success
1933
| E_REQUEST_DENIED - no data behind
1934
+--------------------------------------------------------------------------*/
1935
static int HSC_Horizontal_Half_Line_Backward(FORM * form)
1936
{
1937
return HSC_Generic(form,-((form->current->cols + 1)/2));
1938
}
1939
1940
/*----------------------------------------------------------------------------
1941
End of Horizontal scrolling routines
1942
--------------------------------------------------------------------------*/
1943
1944
/*----------------------------------------------------------------------------
1945
Helper routines for Field Editing
1946
--------------------------------------------------------------------------*/
1947
1948
/*---------------------------------------------------------------------------
1949
| Facility : libnform
1950
| Function : static bool Is_There_Room_For_A_Line(FORM * form)
1951
|
1952
| Description : Check whether or not there is enough room in the
1953
| buffer to enter a whole line.
1954
|
1955
| Return Values : TRUE - there is enough space
1956
| FALSE - there is not enough space
1957
+--------------------------------------------------------------------------*/
1958
INLINE static bool Is_There_Room_For_A_Line(FORM * form)
1959
{
1960
FIELD *field = form->current;
1961
char *begin_of_last_line, *s;
1962
1963
Synchronize_Buffer(form);
1964
begin_of_last_line = Address_Of_Row_In_Buffer(field,(field->drows-1));
1965
s = After_End_Of_Data(begin_of_last_line,field->dcols);
1966
return ((s==begin_of_last_line) ? TRUE : FALSE);
1967
}
1968
1969
/*---------------------------------------------------------------------------
1970
| Facility : libnform
1971
| Function : static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1972
|
1973
| Description : Checks whether or not there is room for a new character
1974
| in the current line.
1975
|
1976
| Return Values : TRUE - there is room
1977
| FALSE - there is not enough room (line full)
1978
+--------------------------------------------------------------------------*/
1979
INLINE static bool Is_There_Room_For_A_Char_In_Line(FORM * form)
1980
{
1981
int last_char_in_line;
1982
1983
wmove(form->w,form->currow,form->current->dcols-1);
1984
last_char_in_line = (int)(winch(form->w) & A_CHARTEXT);
1985
wmove(form->w,form->currow,form->curcol);
1986
return (((last_char_in_line == form->current->pad) ||
1987
is_blank(last_char_in_line)) ? TRUE : FALSE);
1988
}
1989
1990
#define There_Is_No_Room_For_A_Char_In_Line(f) \
1991
!Is_There_Room_For_A_Char_In_Line(f)
1992
1993
/*---------------------------------------------------------------------------
1994
| Facility : libnform
1995
| Function : static int Insert_String(
1996
| FORM * form,
1997
| int row,
1998
| char *txt,
1999
| int len )
2000
|
2001
| Description : Insert the 'len' characters beginning at pointer 'txt'
2002
| into the 'row' of the 'form'. The insertion occurs
2003
| on the beginning of the row, all other characters are
2004
| moved to the right. After the text a pad character will
2005
| be inserted to separate the text from the rest. If
2006
| necessary the insertion moves characters on the next
2007
| line to make place for the requested insertion string.
2008
|
2009
| Return Values : E_OK - success
2010
| E_REQUEST_DENIED -
2011
| E_SYSTEM_ERROR - system error
2012
+--------------------------------------------------------------------------*/
2013
static int Insert_String(FORM *form, int row, char *txt, int len)
2014
{
2015
FIELD *field = form->current;
2016
char *bp = Address_Of_Row_In_Buffer(field,row);
2017
int datalen = (int)(After_End_Of_Data(bp,field->dcols) - bp);
2018
int freelen = field->dcols - datalen;
2019
int requiredlen = len+1;
2020
char *split;
2021
int result = E_REQUEST_DENIED;
2022
char *Space;
2023
2024
Space = (char*)malloc(2*sizeof(char));
2025
strcpy(Space, " ");
2026
2027
if (freelen >= requiredlen)
2028
{
2029
wmove(form->w,row,0);
2030
winsnstr(form->w,txt,len);
2031
wmove(form->w,row,len);
2032
winsnstr(form->w,Space,1);
2033
free(Space);
2034
return E_OK;
2035
}
2036
else
2037
{ /* we have to move characters on the next line. If we are on the
2038
last line this may work, if the field is growable */
2039
if ((row == (field->drows - 1)) && Growable(field))
2040
{
2041
if (!Field_Grown(field,1))
2042
{
2043
free(Space);
2044
return(E_SYSTEM_ERROR);
2045
}
2046
/* !!!Side-Effect : might be changed due to growth!!! */
2047
bp = Address_Of_Row_In_Buffer(field,row);
2048
}
2049
2050
if (row < (field->drows - 1))
2051
{
2052
split = After_Last_Whitespace_Character(bp,
2053
(int)(Get_Start_Of_Data(bp + field->dcols - requiredlen ,
2054
requiredlen) - bp));
2055
/* split points now to the first character of the portion of the
2056
line that must be moved to the next line */
2057
datalen = (int)(split-bp); /* + freelen has to stay on this line */
2058
freelen = field->dcols - (datalen + freelen); /* for the next line */
2059
2060
if ((result=Insert_String(form,row+1,split,freelen))==E_OK)
2061
{
2062
wmove(form->w,row,datalen);
2063
wclrtoeol(form->w);
2064
wmove(form->w,row,0);
2065
winsnstr(form->w,txt,len);
2066
wmove(form->w,row,len);
2067
winsnstr(form->w,Space,1);
2068
free(Space);
2069
return E_OK;
2070
}
2071
}
2072
free(Space);
2073
return(result);
2074
}
2075
}
2076
2077
/*---------------------------------------------------------------------------
2078
| Facility : libnform
2079
| Function : static int Wrapping_Not_Necessary_Or_Wrapping_Ok(
2080
| FORM * form)
2081
|
2082
| Description : If a character has been entered into a field, it may
2083
| be that wrapping has to occur. This routine checks
2084
| whether or not wrapping is required and if so, performs
2085
| the wrapping.
2086
|
2087
| Return Values : E_OK - no wrapping required or wrapping
2088
| was successful
2089
| E_REQUEST_DENIED -
2090
| E_SYSTEM_ERROR - some system error
2091
+--------------------------------------------------------------------------*/
2092
static int Wrapping_Not_Necessary_Or_Wrapping_Ok(FORM * form)
2093
{
2094
FIELD *field = form->current;
2095
int result = E_REQUEST_DENIED;
2096
bool Last_Row = ((field->drows - 1) == form->currow);
2097
2098
if ( (field->opts & O_WRAP) && /* wrapping wanted */
2099
(!Single_Line_Field(field)) && /* must be multi-line */
2100
(There_Is_No_Room_For_A_Char_In_Line(form)) && /* line is full */
2101
(!Last_Row || Growable(field)) ) /* there are more lines*/
2102
{
2103
char *bp;
2104
char *split;
2105
int chars_to_be_wrapped;
2106
int chars_to_remain_on_line;
2107
if (Last_Row)
2108
{ /* the above logic already ensures, that in this case the field
2109
is growable */
2110
if (!Field_Grown(field,1))
2111
return E_SYSTEM_ERROR;
2112
}
2113
bp = Address_Of_Current_Row_In_Buffer(form);
2114
Window_To_Buffer(form->w,field);
2115
split = After_Last_Whitespace_Character(bp,field->dcols);
2116
/* split points to the first character of the sequence to be brought
2117
on the next line */
2118
chars_to_remain_on_line = (int)(split - bp);
2119
chars_to_be_wrapped = field->dcols - chars_to_remain_on_line;
2120
if (chars_to_remain_on_line > 0)
2121
{
2122
if ((result=Insert_String(form,form->currow+1,split,
2123
chars_to_be_wrapped)) == E_OK)
2124
{
2125
wmove(form->w,form->currow,chars_to_remain_on_line);
2126
wclrtoeol(form->w);
2127
if (form->curcol >= chars_to_remain_on_line)
2128
{
2129
form->currow++;
2130
form->curcol -= chars_to_remain_on_line;
2131
}
2132
return E_OK;
2133
}
2134
}
2135
else
2136
return E_OK;
2137
if (result!=E_OK)
2138
{
2139
wmove(form->w,form->currow,form->curcol);
2140
wdelch(form->w);
2141
Window_To_Buffer(form->w,field);
2142
result = E_REQUEST_DENIED;
2143
}
2144
}
2145
else
2146
result = E_OK; /* wrapping was not necessary */
2147
return(result);
2148
}
2149
2150
/*----------------------------------------------------------------------------
2151
Field Editing routines
2152
--------------------------------------------------------------------------*/
2153
2154
/*---------------------------------------------------------------------------
2155
| Facility : libnform
2156
| Function : static int Field_Editing(
2157
| int (* const fct) (FORM *),
2158
| FORM * form)
2159
|
2160
| Description : Generic routine for field editing requests. The driver
2161
| routines are only called for editable fields, the
2162
| _WINDOW_MODIFIED flag is set if editing occurred.
2163
| This is somewhat special due to the overload semantics
2164
| of the NEW_LINE and DEL_PREV requests.
2165
|
2166
| Return Values : Error code from low level drivers.
2167
+--------------------------------------------------------------------------*/
2168
static int Field_Editing(int (* const fct) (FORM *), FORM * form)
2169
{
2170
int res = E_REQUEST_DENIED;
2171
2172
/* We have to deal here with the specific case of the overloaded
2173
behaviour of New_Line and Delete_Previous requests.
2174
They may end up in navigational requests if we are on the first
2175
character in a field. But navigation is also allowed on non-
2176
editable fields.
2177
*/
2178
if ((fct==FE_Delete_Previous) &&
2179
(form->opts & O_BS_OVERLOAD) &&
2180
First_Position_In_Current_Field(form) )
2181
{
2182
res = Inter_Field_Navigation(FN_Previous_Field,form);
2183
}
2184
else
2185
{
2186
if (fct==FE_New_Line)
2187
{
2188
if ((form->opts & O_NL_OVERLOAD) &&
2189
First_Position_In_Current_Field(form))
2190
{
2191
res = Inter_Field_Navigation(FN_Next_Field,form);
2192
}
2193
else
2194
/* FE_New_Line deals itself with the _WINDOW_MODIFIED flag */
2195
res = fct(form);
2196
}
2197
else
2198
{
2199
/* From now on, everything must be editable */
2200
if (form->current->opts & O_EDIT)
2201
{
2202
res = fct(form);
2203
if (res==E_OK)
2204
form->status |= _WINDOW_MODIFIED;
2205
}
2206
}
2207
}
2208
return res;
2209
}
2210
2211
/*---------------------------------------------------------------------------
2212
| Facility : libnform
2213
| Function : static int FE_New_Line(FORM * form)
2214
|
2215
| Description : Perform a new line request. This is rather complex
2216
| compared to other routines in this code due to the
2217
| rather difficult to understand description in the
2218
| manuals.
2219
|
2220
| Return Values : E_OK - success
2221
| E_REQUEST_DENIED - new line not allowed
2222
| E_SYSTEM_ERROR - system error
2223
+--------------------------------------------------------------------------*/
2224
static int FE_New_Line(FORM * form)
2225
{
2226
FIELD *field = form->current;
2227
char *bp, *t;
2228
bool Last_Row = ((field->drows - 1)==form->currow);
2229
2230
if (form->status & _OVLMODE)
2231
{
2232
if (Last_Row &&
2233
(!(Growable(field) && !Single_Line_Field(field))))
2234
{
2235
if (!(form->opts & O_NL_OVERLOAD))
2236
return(E_REQUEST_DENIED);
2237
wclrtoeol(form->w);
2238
/* we have to set this here, although it is also
2239
handled in the generic routine. The reason is,
2240
that FN_Next_Field may fail, but the form is
2241
definitively changed */
2242
form->status |= _WINDOW_MODIFIED;
2243
return Inter_Field_Navigation(FN_Next_Field,form);
2244
}
2245
else
2246
{
2247
if (Last_Row && !Field_Grown(field,1))
2248
{ /* N.B.: due to the logic in the 'if', LastRow==TRUE
2249
means here that the field is growable and not
2250
a single-line field */
2251
return(E_SYSTEM_ERROR);
2252
}
2253
wclrtoeol(form->w);
2254
form->currow++;
2255
form->curcol = 0;
2256
form->status |= _WINDOW_MODIFIED;
2257
return(E_OK);
2258
}
2259
}
2260
else
2261
{ /* Insert Mode */
2262
if (Last_Row &&
2263
!(Growable(field) && !Single_Line_Field(field)))
2264
{
2265
if (!(form->opts & O_NL_OVERLOAD))
2266
return(E_REQUEST_DENIED);
2267
return Inter_Field_Navigation(FN_Next_Field,form);
2268
}
2269
else
2270
{
2271
bool May_Do_It = !Last_Row && Is_There_Room_For_A_Line(form);
2272
2273
if (!(May_Do_It || Growable(field)))
2274
return(E_REQUEST_DENIED);
2275
if (!May_Do_It && !Field_Grown(field,1))
2276
return(E_SYSTEM_ERROR);
2277
2278
bp= Address_Of_Current_Position_In_Buffer(form);
2279
t = After_End_Of_Data(bp,field->dcols - form->curcol);
2280
wclrtoeol(form->w);
2281
form->currow++;
2282
form->curcol=0;
2283
wmove(form->w,form->currow,form->curcol);
2284
winsertln(form->w);
2285
waddnstr(form->w,bp,(int)(t-bp));
2286
form->status |= _WINDOW_MODIFIED;
2287
return E_OK;
2288
}
2289
}
2290
}
2291
2292
/*---------------------------------------------------------------------------
2293
| Facility : libnform
2294
| Function : static int FE_Insert_Character(FORM * form)
2295
|
2296
| Description : Insert blank character at the cursor position
2297
|
2298
| Return Values : E_OK
2299
| E_REQUEST_DENIED
2300
+--------------------------------------------------------------------------*/
2301
static int FE_Insert_Character(FORM * form)
2302
{
2303
FIELD *field = form->current;
2304
int result = E_REQUEST_DENIED;
2305
2306
if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2307
{
2308
bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
2309
2310
if (There_Is_Room ||
2311
((Single_Line_Field(field) && Growable(field))))
2312
{
2313
if (!There_Is_Room && !Field_Grown(field,1))
2314
result = E_SYSTEM_ERROR;
2315
else
2316
{
2317
winsch(form->w,(chtype)C_BLANK);
2318
result = Wrapping_Not_Necessary_Or_Wrapping_Ok(form);
2319
}
2320
}
2321
}
2322
return result;
2323
}
2324
2325
/*---------------------------------------------------------------------------
2326
| Facility : libnform
2327
| Function : static int FE_Insert_Line(FORM * form)
2328
|
2329
| Description : Insert a blank line at the cursor position
2330
|
2331
| Return Values : E_OK - success
2332
| E_REQUEST_DENIED - line can not be inserted
2333
+--------------------------------------------------------------------------*/
2334
static int FE_Insert_Line(FORM * form)
2335
{
2336
FIELD *field = form->current;
2337
int result = E_REQUEST_DENIED;
2338
2339
if (Check_Char(field->type,(int)C_BLANK,(TypeArgument *)(field->arg)))
2340
{
2341
bool Maybe_Done = (form->currow!=(field->drows-1)) &&
2342
Is_There_Room_For_A_Line(form);
2343
2344
if (!Single_Line_Field(field) &&
2345
(Maybe_Done || Growable(field)))
2346
{
2347
if (!Maybe_Done && !Field_Grown(field,1))
2348
result = E_SYSTEM_ERROR;
2349
else
2350
{
2351
form->curcol = 0;
2352
winsertln(form->w);
2353
result = E_OK;
2354
}
2355
}
2356
}
2357
return result;
2358
}
2359
2360
/*---------------------------------------------------------------------------
2361
| Facility : libnform
2362
| Function : static int FE_Delete_Character(FORM * form)
2363
|
2364
| Description : Delete character at the cursor position
2365
|
2366
| Return Values : E_OK - success
2367
+--------------------------------------------------------------------------*/
2368
static int FE_Delete_Character(FORM * form)
2369
{
2370
wdelch(form->w);
2371
return E_OK;
2372
}
2373
2374
/*---------------------------------------------------------------------------
2375
| Facility : libnform
2376
| Function : static int FE_Delete_Previous(FORM * form)
2377
|
2378
| Description : Delete character before cursor. Again this is a rather
2379
| difficult piece compared to others due to the overloading
2380
| semantics of backspace.
2381
| N.B.: The case of overloaded BS on first field position
2382
| is already handled in the generic routine.
2383
|
2384
| Return Values : E_OK - success
2385
| E_REQUEST_DENIED - Character can't be deleted
2386
+--------------------------------------------------------------------------*/
2387
static int FE_Delete_Previous(FORM * form)
2388
{
2389
FIELD *field = form->current;
2390
2391
if (First_Position_In_Current_Field(form))
2392
return E_REQUEST_DENIED;
2393
2394
if ( (--(form->curcol))<0 )
2395
{
2396
char *this_line, *prev_line, *prev_end, *this_end;
2397
2398
form->curcol++;
2399
if (form->status & _OVLMODE)
2400
return E_REQUEST_DENIED;
2401
2402
prev_line = Address_Of_Row_In_Buffer(field,(form->currow-1));
2403
this_line = Address_Of_Row_In_Buffer(field,(form->currow));
2404
Synchronize_Buffer(form);
2405
prev_end = After_End_Of_Data(prev_line,field->dcols);
2406
this_end = After_End_Of_Data(this_line,field->dcols);
2407
if ((int)(this_end-this_line) >
2408
(field->cols-(int)(prev_end-prev_line)))
2409
return E_REQUEST_DENIED;
2410
wdeleteln(form->w);
2411
Adjust_Cursor_Position(form,prev_end);
2412
wmove(form->w,form->currow,form->curcol);
2413
waddnstr(form->w,this_line,(int)(this_end-this_line));
2414
}
2415
else
2416
{
2417
wmove(form->w,form->currow,form->curcol);
2418
wdelch(form->w);
2419
}
2420
return E_OK;
2421
}
2422
2423
/*---------------------------------------------------------------------------
2424
| Facility : libnform
2425
| Function : static int FE_Delete_Line(FORM * form)
2426
|
2427
| Description : Delete line at cursor position.
2428
|
2429
| Return Values : E_OK - success
2430
+--------------------------------------------------------------------------*/
2431
static int FE_Delete_Line(FORM * form)
2432
{
2433
form->curcol = 0;
2434
wdeleteln(form->w);
2435
return E_OK;
2436
}
2437
2438
/*---------------------------------------------------------------------------
2439
| Facility : libnform
2440
| Function : static int FE_Delete_Word(FORM * form)
2441
|
2442
| Description : Delete word at cursor position
2443
|
2444
| Return Values : E_OK - success
2445
| E_REQUEST_DENIED - failure
2446
+--------------------------------------------------------------------------*/
2447
static int FE_Delete_Word(FORM * form)
2448
{
2449
FIELD *field = form->current;
2450
char *bp = Address_Of_Current_Row_In_Buffer(form);
2451
char *ep = bp + field->dcols;
2452
char *cp = bp + form->curcol;
2453
char *s;
2454
2455
Synchronize_Buffer(form);
2456
if (is_blank(*cp))
2457
return E_REQUEST_DENIED; /* not in word */
2458
2459
/* move cursor to begin of word and erase to end of screen-line */
2460
Adjust_Cursor_Position(form,
2461
After_Last_Whitespace_Character(bp,form->curcol));
2462
wmove(form->w,form->currow,form->curcol);
2463
wclrtoeol(form->w);
2464
2465
/* skip over word in buffer */
2466
s = Get_First_Whitespace_Character(cp,(int)(ep-cp));
2467
/* to begin of next word */
2468
s = Get_Start_Of_Data(s,(int)(ep - s));
2469
if ( (s!=cp) && !is_blank(*s))
2470
{
2471
/* copy remaining line to window */
2472
waddnstr(form->w,s,(int)(s - After_End_Of_Data(s,(int)(ep - s))));
2473
}
2474
return E_OK;
2475
}
2476
2477
/*---------------------------------------------------------------------------
2478
| Facility : libnform
2479
| Function : static int FE_Clear_To_End_Of_Line(FORM * form)
2480
|
2481
| Description : Clear to end of current line.
2482
|
2483
| Return Values : E_OK - success
2484
+--------------------------------------------------------------------------*/
2485
static int FE_Clear_To_End_Of_Line(FORM * form)
2486
{
2487
wclrtoeol(form->w);
2488
return E_OK;
2489
}
2490
2491
/*---------------------------------------------------------------------------
2492
| Facility : libnform
2493
| Function : static int FE_Clear_To_End_Of_Form(FORM * form)
2494
|
2495
| Description : Clear to end of form.
2496
|
2497
| Return Values : E_OK - success
2498
+--------------------------------------------------------------------------*/
2499
static int FE_Clear_To_End_Of_Form(FORM * form)
2500
{
2501
wclrtobot(form->w);
2502
return E_OK;
2503
}
2504
2505
/*---------------------------------------------------------------------------
2506
| Facility : libnform
2507
| Function : static int FE_Clear_Field(FORM * form)
2508
|
2509
| Description : Clear entire field.
2510
|
2511
| Return Values : E_OK - success
2512
+--------------------------------------------------------------------------*/
2513
static int FE_Clear_Field(FORM * form)
2514
{
2515
form->currow = form->curcol = 0;
2516
werase(form->w);
2517
return E_OK;
2518
}
2519
/*----------------------------------------------------------------------------
2520
END of Field Editing routines
2521
--------------------------------------------------------------------------*/
2522
2523
/*----------------------------------------------------------------------------
2524
Edit Mode routines
2525
--------------------------------------------------------------------------*/
2526
2527
/*---------------------------------------------------------------------------
2528
| Facility : libnform
2529
| Function : static int EM_Overlay_Mode(FORM * form)
2530
|
2531
| Description : Switch to overlay mode.
2532
|
2533
| Return Values : E_OK - success
2534
+--------------------------------------------------------------------------*/
2535
static int EM_Overlay_Mode(FORM * form)
2536
{
2537
form->status |= _OVLMODE;
2538
return E_OK;
2539
}
2540
2541
/*---------------------------------------------------------------------------
2542
| Facility : libnform
2543
| Function : static int EM_Insert_Mode(FORM * form)
2544
|
2545
| Description : Switch to insert mode
2546
|
2547
| Return Values : E_OK - success
2548
+--------------------------------------------------------------------------*/
2549
static int EM_Insert_Mode(FORM * form)
2550
{
2551
form->status &= ~_OVLMODE;
2552
return E_OK;
2553
}
2554
2555
/*----------------------------------------------------------------------------
2556
END of Edit Mode routines
2557
--------------------------------------------------------------------------*/
2558
2559
/*----------------------------------------------------------------------------
2560
Helper routines for Choice Requests
2561
--------------------------------------------------------------------------*/
2562
2563
/*---------------------------------------------------------------------------
2564
| Facility : libnform
2565
| Function : static bool Next_Choice(
2566
| FIELDTYPE * typ,
2567
| FIELD * field,
2568
| TypeArgument *argp)
2569
|
2570
| Description : Get the next field choice. For linked types this is
2571
| done recursively.
2572
|
2573
| Return Values : TRUE - next choice successfully retrieved
2574
| FALSE - couldn't retrieve next choice
2575
+--------------------------------------------------------------------------*/
2576
static bool Next_Choice(FIELDTYPE * typ, FIELD *field, TypeArgument *argp)
2577
{
2578
if (!typ || !(typ->status & _HAS_CHOICE))
2579
return FALSE;
2580
2581
if (typ->status & _LINKED_TYPE)
2582
{
2583
assert(argp != 0);
2584
return(
2585
Next_Choice(typ->left ,field,argp->left) ||
2586
Next_Choice(typ->right,field,argp->right) );
2587
}
2588
else
2589
{
2590
assert(typ->next != 0);
2591
return typ->next(field,(void *)argp);
2592
}
2593
}
2594
2595
/*---------------------------------------------------------------------------
2596
| Facility : libnform
2597
| Function : static bool Previous_Choice(
2598
| FIELDTYPE * typ,
2599
| FIELD * field,
2600
| TypeArgument *argp)
2601
|
2602
| Description : Get the previous field choice. For linked types this
2603
| is done recursively.
2604
|
2605
| Return Values : TRUE - previous choice successfully retrieved
2606
| FALSE - couldn't retrieve previous choice
2607
+--------------------------------------------------------------------------*/
2608
static bool Previous_Choice(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2609
{
2610
if (!typ || !(typ->status & _HAS_CHOICE))
2611
return FALSE;
2612
2613
if (typ->status & _LINKED_TYPE)
2614
{
2615
assert(argp != 0);
2616
return(
2617
Previous_Choice(typ->left ,field,argp->left) ||
2618
Previous_Choice(typ->right,field,argp->right));
2619
}
2620
else
2621
{
2622
assert(typ->prev != 0);
2623
return typ->prev(field,(void *)argp);
2624
}
2625
}
2626
/*----------------------------------------------------------------------------
2627
End of Helper routines for Choice Requests
2628
--------------------------------------------------------------------------*/
2629
2630
/*----------------------------------------------------------------------------
2631
Routines for Choice Requests
2632
--------------------------------------------------------------------------*/
2633
2634
/*---------------------------------------------------------------------------
2635
| Facility : libnform
2636
| Function : static int CR_Next_Choice(FORM * form)
2637
|
2638
| Description : Get the next field choice.
2639
|
2640
| Return Values : E_OK - success
2641
| E_REQUEST_DENIED - next choice couldn't be retrieved
2642
+--------------------------------------------------------------------------*/
2643
static int CR_Next_Choice(FORM * form)
2644
{
2645
FIELD *field = form->current;
2646
Synchronize_Buffer(form);
2647
return ((Next_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2648
E_OK : E_REQUEST_DENIED);
2649
}
2650
2651
/*---------------------------------------------------------------------------
2652
| Facility : libnform
2653
| Function : static int CR_Previous_Choice(FORM * form)
2654
|
2655
| Description : Get the previous field choice.
2656
|
2657
| Return Values : E_OK - success
2658
| E_REQUEST_DENIED - prev. choice couldn't be retrieved
2659
+--------------------------------------------------------------------------*/
2660
static int CR_Previous_Choice(FORM * form)
2661
{
2662
FIELD *field = form->current;
2663
Synchronize_Buffer(form);
2664
return ((Previous_Choice(field->type,field,(TypeArgument *)(field->arg))) ?
2665
E_OK : E_REQUEST_DENIED);
2666
}
2667
/*----------------------------------------------------------------------------
2668
End of Routines for Choice Requests
2669
--------------------------------------------------------------------------*/
2670
2671
/*----------------------------------------------------------------------------
2672
Helper routines for Field Validations.
2673
--------------------------------------------------------------------------*/
2674
2675
/*---------------------------------------------------------------------------
2676
| Facility : libnform
2677
| Function : static bool Check_Field(
2678
| FIELDTYPE * typ,
2679
| FIELD * field,
2680
| TypeArgument * argp)
2681
|
2682
| Description : Check the field according to its fieldtype and its
2683
| actual arguments. For linked fieldtypes this is done
2684
| recursively.
2685
|
2686
| Return Values : TRUE - field is valid
2687
| FALSE - field is invalid.
2688
+--------------------------------------------------------------------------*/
2689
static bool Check_Field(FIELDTYPE *typ, FIELD *field, TypeArgument *argp)
2690
{
2691
if (typ)
2692
{
2693
if (field->opts & O_NULLOK)
2694
{
2695
char *bp = field->buf;
2696
assert(bp != 0);
2697
while(is_blank(*bp))
2698
{ bp++; }
2699
if (*bp == '\0')
2700
return TRUE;
2701
}
2702
2703
if (typ->status & _LINKED_TYPE)
2704
{
2705
assert(argp != 0);
2706
return(
2707
Check_Field(typ->left ,field,argp->left ) ||
2708
Check_Field(typ->right,field,argp->right) );
2709
}
2710
else
2711
{
2712
if (typ->fcheck)
2713
return typ->fcheck(field,(void *)argp);
2714
}
2715
}
2716
return TRUE;
2717
}
2718
2719
/*---------------------------------------------------------------------------
2720
| Facility : libnform
2721
| Function : bool _nc_Internal_Validation(FORM * form )
2722
|
2723
| Description : Validate the current field of the form.
2724
|
2725
| Return Values : TRUE - field is valid
2726
| FALSE - field is invalid
2727
+--------------------------------------------------------------------------*/
2728
bool
2729
_nc_Internal_Validation(FORM *form)
2730
{
2731
FIELD *field;
2732
2733
field = form->current;
2734
2735
Synchronize_Buffer(form);
2736
if ((form->status & _FCHECK_REQUIRED) ||
2737
(!(field->opts & O_PASSOK)))
2738
{
2739
if (!Check_Field(field->type,field,(TypeArgument *)(field->arg)))
2740
return FALSE;
2741
form->status &= ~_FCHECK_REQUIRED;
2742
field->status |= _CHANGED;
2743
Synchronize_Linked_Fields(field);
2744
}
2745
return TRUE;
2746
}
2747
/*----------------------------------------------------------------------------
2748
End of Helper routines for Field Validations.
2749
--------------------------------------------------------------------------*/
2750
2751
/*----------------------------------------------------------------------------
2752
Routines for Field Validation.
2753
--------------------------------------------------------------------------*/
2754
2755
/*---------------------------------------------------------------------------
2756
| Facility : libnform
2757
| Function : static int FV_Validation(FORM * form)
2758
|
2759
| Description : Validate the current field of the form.
2760
|
2761
| Return Values : E_OK - field valid
2762
| E_INVALID_FIELD - field not valid
2763
+--------------------------------------------------------------------------*/
2764
static int FV_Validation(FORM * form)
2765
{
2766
if (_nc_Internal_Validation(form))
2767
return E_OK;
2768
else
2769
return E_INVALID_FIELD;
2770
}
2771
/*----------------------------------------------------------------------------
2772
End of routines for Field Validation.
2773
--------------------------------------------------------------------------*/
2774
2775
/*----------------------------------------------------------------------------
2776
Helper routines for Inter-Field Navigation
2777
--------------------------------------------------------------------------*/
2778
2779
/*---------------------------------------------------------------------------
2780
| Facility : libnform
2781
| Function : static FIELD *Next_Field_On_Page(FIELD * field)
2782
|
2783
| Description : Get the next field after the given field on the current
2784
| page. The order of fields is the one defined by the
2785
| fields array. Only visible and active fields are
2786
| counted.
2787
|
2788
| Return Values : Pointer to the next field.
2789
+--------------------------------------------------------------------------*/
2790
INLINE static FIELD *Next_Field_On_Page(FIELD * field)
2791
{
2792
FORM *form = field->form;
2793
FIELD **field_on_page = &form->field[field->index];
2794
FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2795
FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2796
2797
do
2798
{
2799
field_on_page =
2800
(field_on_page==last_on_page) ? first_on_page : field_on_page + 1;
2801
if (Field_Is_Selectable(*field_on_page))
2802
break;
2803
} while(field!=(*field_on_page));
2804
return(*field_on_page);
2805
}
2806
2807
/*---------------------------------------------------------------------------
2808
| Facility : libnform
2809
| Function : FIELD* _nc_First_Active_Field(FORM * form)
2810
|
2811
| Description : Get the first active field on the current page,
2812
| if there are such. If there are none, get the first
2813
| visible field on the page. If there are also none,
2814
| we return the first field on page and hope the best.
2815
|
2816
| Return Values : Pointer to calculated field.
2817
+--------------------------------------------------------------------------*/
2818
FIELD*
2819
_nc_First_Active_Field(FORM * form)
2820
{
2821
FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2822
FIELD *proposed = Next_Field_On_Page(*last_on_page);
2823
2824
if (proposed == *last_on_page)
2825
{ /* there might be the special situation, where there is no
2826
active and visible field on the current page. We then select
2827
the first visible field on this readonly page
2828
*/
2829
if (Field_Is_Not_Selectable(proposed))
2830
{
2831
FIELD **field = &form->field[proposed->index];
2832
FIELD **first = &form->field[form->page[form->curpage].pmin];
2833
2834
do
2835
{
2836
field = (field==last_on_page) ? first : field + 1;
2837
if (((*field)->opts & O_VISIBLE))
2838
break;
2839
} while(proposed!=(*field));
2840
2841
proposed = *field;
2842
2843
if ((proposed == *last_on_page) && !(proposed->opts&O_VISIBLE))
2844
{ /* This means, there is also no visible field on the page.
2845
So we propose the first one and hope the very best...
2846
Some very clever user has designed a readonly and invisible
2847
page on this form.
2848
*/
2849
proposed = *first;
2850
}
2851
}
2852
}
2853
return(proposed);
2854
}
2855
2856
/*---------------------------------------------------------------------------
2857
| Facility : libnform
2858
| Function : static FIELD *Previous_Field_On_Page(FIELD * field)
2859
|
2860
| Description : Get the previous field before the given field on the
2861
| current page. The order of fields is the one defined by
2862
| the fields array. Only visible and active fields are
2863
| counted.
2864
|
2865
| Return Values : Pointer to the previous field.
2866
+--------------------------------------------------------------------------*/
2867
INLINE static FIELD *Previous_Field_On_Page(FIELD * field)
2868
{
2869
FORM *form = field->form;
2870
FIELD **field_on_page = &form->field[field->index];
2871
FIELD **first_on_page = &form->field[form->page[form->curpage].pmin];
2872
FIELD **last_on_page = &form->field[form->page[form->curpage].pmax];
2873
2874
do
2875
{
2876
field_on_page =
2877
(field_on_page==first_on_page) ? last_on_page : field_on_page - 1;
2878
if (Field_Is_Selectable(*field_on_page))
2879
break;
2880
} while(field!=(*field_on_page));
2881
2882
return (*field_on_page);
2883
}
2884
2885
/*---------------------------------------------------------------------------
2886
| Facility : libnform
2887
| Function : static FIELD *Sorted_Next_Field(FIELD * field)
2888
|
2889
| Description : Get the next field after the given field on the current
2890
| page. The order of fields is the one defined by the
2891
| (row,column) geometry, rows are major.
2892
|
2893
| Return Values : Pointer to the next field.
2894
+--------------------------------------------------------------------------*/
2895
INLINE static FIELD *Sorted_Next_Field(FIELD * field)
2896
{
2897
FIELD *field_on_page = field;
2898
2899
do
2900
{
2901
field_on_page = field_on_page->snext;
2902
if (Field_Is_Selectable(field_on_page))
2903
break;
2904
} while(field_on_page!=field);
2905
2906
return (field_on_page);
2907
}
2908
2909
/*---------------------------------------------------------------------------
2910
| Facility : libnform
2911
| Function : static FIELD *Sorted_Previous_Field(FIELD * field)
2912
|
2913
| Description : Get the previous field before the given field on the
2914
| current page. The order of fields is the one defined
2915
| by the (row,column) geometry, rows are major.
2916
|
2917
| Return Values : Pointer to the previous field.
2918
+--------------------------------------------------------------------------*/
2919
INLINE static FIELD *Sorted_Previous_Field(FIELD * field)
2920
{
2921
FIELD *field_on_page = field;
2922
2923
do
2924
{
2925
field_on_page = field_on_page->sprev;
2926
if (Field_Is_Selectable(field_on_page))
2927
break;
2928
} while(field_on_page!=field);
2929
2930
return (field_on_page);
2931
}
2932
2933
/*---------------------------------------------------------------------------
2934
| Facility : libnform
2935
| Function : static FIELD *Left_Neighbour_Field(FIELD * field)
2936
|
2937
| Description : Get the left neighbour of the field on the same line
2938
| and the same page. Cycles through the line.
2939
|
2940
| Return Values : Pointer to left neighbour field.
2941
+--------------------------------------------------------------------------*/
2942
INLINE static FIELD *Left_Neighbour_Field(FIELD * field)
2943
{
2944
FIELD *field_on_page = field;
2945
2946
/* For a field that has really a left neighbour, the while clause
2947
immediately fails and the loop is left, positioned at the right
2948
neighbour. Otherwise we cycle backwards through the sorted fieldlist
2949
until we enter the same line (from the right end).
2950
*/
2951
do
2952
{
2953
field_on_page = Sorted_Previous_Field(field_on_page);
2954
} while(field_on_page->frow != field->frow);
2955
2956
return (field_on_page);
2957
}
2958
2959
/*---------------------------------------------------------------------------
2960
| Facility : libnform
2961
| Function : static FIELD *Right_Neighbour_Field(FIELD * field)
2962
|
2963
| Description : Get the right neighbour of the field on the same line
2964
| and the same page.
2965
|
2966
| Return Values : Pointer to right neighbour field.
2967
+--------------------------------------------------------------------------*/
2968
INLINE static FIELD *Right_Neighbour_Field(FIELD * field)
2969
{
2970
FIELD *field_on_page = field;
2971
2972
/* See the comments on Left_Neighbour_Field to understand how it works */
2973
do
2974
{
2975
field_on_page = Sorted_Next_Field(field_on_page);
2976
} while(field_on_page->frow != field->frow);
2977
2978
return (field_on_page);
2979
}
2980
2981
/*---------------------------------------------------------------------------
2982
| Facility : libnform
2983
| Function : static FIELD *Upper_Neighbour_Field(FIELD * field)
2984
|
2985
| Description : Because of the row-major nature of sorting the fields,
2986
| its more difficult to define what's the upper neighbour
2987
| field really means. We define that it must be on a
2988
| 'previous' line (cyclic order!) and is the rightmost
2989
| field laying on the left side of the given field. If
2990
| this set is empty, we take the first field on the line.
2991
|
2992
| Return Values : Pointer to the upper neighbour field.
2993
+--------------------------------------------------------------------------*/
2994
static FIELD *Upper_Neighbour_Field(FIELD * field)
2995
{
2996
FIELD *field_on_page = field;
2997
int frow = field->frow;
2998
int fcol = field->fcol;
2999
3000
/* Walk back to the 'previous' line. The second term in the while clause
3001
just guarantees that we stop if we cycled through the line because
3002
there might be no 'previous' line if the page has just one line.
3003
*/
3004
do
3005
{
3006
field_on_page = Sorted_Previous_Field(field_on_page);
3007
} while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3008
3009
if (field_on_page->frow!=frow)
3010
{ /* We really found a 'previous' line. We are positioned at the
3011
rightmost field on this line */
3012
frow = field_on_page->frow;
3013
3014
/* We walk to the left as long as we are really right of the
3015
field. */
3016
while(field_on_page->frow==frow && field_on_page->fcol>fcol)
3017
field_on_page = Sorted_Previous_Field(field_on_page);
3018
3019
/* If we wrapped, just go to the right which is the first field on
3020
the row */
3021
if (field_on_page->frow!=frow)
3022
field_on_page = Sorted_Next_Field(field_on_page);
3023
}
3024
3025
return (field_on_page);
3026
}
3027
3028
/*---------------------------------------------------------------------------
3029
| Facility : libnform
3030
| Function : static FIELD *Down_Neighbour_Field(FIELD * field)
3031
|
3032
| Description : Because of the row-major nature of sorting the fields,
3033
| its more difficult to define what's the down neighbour
3034
| field really means. We define that it must be on a
3035
| 'next' line (cyclic order!) and is the leftmost
3036
| field laying on the right side of the given field. If
3037
| this set is empty, we take the last field on the line.
3038
|
3039
| Return Values : Pointer to the upper neighbour field.
3040
+--------------------------------------------------------------------------*/
3041
static FIELD *Down_Neighbour_Field(FIELD * field)
3042
{
3043
FIELD *field_on_page = field;
3044
int frow = field->frow;
3045
int fcol = field->fcol;
3046
3047
/* Walk forward to the 'next' line. The second term in the while clause
3048
just guarantees that we stop if we cycled through the line because
3049
there might be no 'next' line if the page has just one line.
3050
*/
3051
do
3052
{
3053
field_on_page = Sorted_Next_Field(field_on_page);
3054
} while(field_on_page->frow==frow && field_on_page->fcol!=fcol);
3055
3056
if (field_on_page->frow!=frow)
3057
{ /* We really found a 'next' line. We are positioned at the rightmost
3058
field on this line */
3059
frow = field_on_page->frow;
3060
3061
/* We walk to the right as long as we are really left of the
3062
field. */
3063
while(field_on_page->frow==frow && field_on_page->fcol<fcol)
3064
field_on_page = Sorted_Next_Field(field_on_page);
3065
3066
/* If we wrapped, just go to the left which is the last field on
3067
the row */
3068
if (field_on_page->frow!=frow)
3069
field_on_page = Sorted_Previous_Field(field_on_page);
3070
}
3071
3072
return(field_on_page);
3073
}
3074
3075
/*----------------------------------------------------------------------------
3076
Inter-Field Navigation routines
3077
--------------------------------------------------------------------------*/
3078
3079
/*---------------------------------------------------------------------------
3080
| Facility : libnform
3081
| Function : static int Inter_Field_Navigation(
3082
| int (* const fct) (FORM *),
3083
| FORM * form)
3084
|
3085
| Description : Generic behaviour for changing the current field, the
3086
| field is left and a new field is entered. So the field
3087
| must be validated and the field init/term hooks must
3088
| be called.
3089
|
3090
| Return Values : E_OK - success
3091
| E_INVALID_FIELD - field is invalid
3092
| some other - error from subordinate call
3093
+--------------------------------------------------------------------------*/
3094
static int Inter_Field_Navigation(int (* const fct) (FORM *),FORM *form)
3095
{
3096
int res;
3097
3098
if (!_nc_Internal_Validation(form))
3099
res = E_INVALID_FIELD;
3100
else
3101
{
3102
Call_Hook(form,fieldterm);
3103
res = fct(form);
3104
Call_Hook(form,fieldinit);
3105
}
3106
return res;
3107
}
3108
3109
/*---------------------------------------------------------------------------
3110
| Facility : libnform
3111
| Function : static int FN_Next_Field(FORM * form)
3112
|
3113
| Description : Move to the next field on the current page of the form
3114
|
3115
| Return Values : E_OK - success
3116
| != E_OK - error from subordinate call
3117
+--------------------------------------------------------------------------*/
3118
static int FN_Next_Field(FORM * form)
3119
{
3120
return _nc_Set_Current_Field(form,
3121
Next_Field_On_Page(form->current));
3122
}
3123
3124
/*---------------------------------------------------------------------------
3125
| Facility : libnform
3126
| Function : static int FN_Previous_Field(FORM * form)
3127
|
3128
| Description : Move to the previous field on the current page of the
3129
| form
3130
|
3131
| Return Values : E_OK - success
3132
| != E_OK - error from subordinate call
3133
+--------------------------------------------------------------------------*/
3134
static int FN_Previous_Field(FORM * form)
3135
{
3136
return _nc_Set_Current_Field(form,
3137
Previous_Field_On_Page(form->current));
3138
}
3139
3140
/*---------------------------------------------------------------------------
3141
| Facility : libnform
3142
| Function : static int FN_First_Field(FORM * form)
3143
|
3144
| Description : Move to the first field on the current page of the form
3145
|
3146
| Return Values : E_OK - success
3147
| != E_OK - error from subordinate call
3148
+--------------------------------------------------------------------------*/
3149
static int FN_First_Field(FORM * form)
3150
{
3151
return _nc_Set_Current_Field(form,
3152
Next_Field_On_Page(form->field[form->page[form->curpage].pmax]));
3153
}
3154
3155
/*---------------------------------------------------------------------------
3156
| Facility : libnform
3157
| Function : static int FN_Last_Field(FORM * form)
3158
|
3159
| Description : Move to the last field on the current page of the form
3160
|
3161
| Return Values : E_OK - success
3162
| != E_OK - error from subordinate call
3163
+--------------------------------------------------------------------------*/
3164
static int FN_Last_Field(FORM * form)
3165
{
3166
return
3167
_nc_Set_Current_Field(form,
3168
Previous_Field_On_Page(form->field[form->page[form->curpage].pmin]));
3169
}
3170
3171
/*---------------------------------------------------------------------------
3172
| Facility : libnform
3173
| Function : static int FN_Sorted_Next_Field(FORM * form)
3174
|
3175
| Description : Move to the sorted next field on the current page
3176
| of the form.
3177
|
3178
| Return Values : E_OK - success
3179
| != E_OK - error from subordinate call
3180
+--------------------------------------------------------------------------*/
3181
static int FN_Sorted_Next_Field(FORM * form)
3182
{
3183
return _nc_Set_Current_Field(form,
3184
Sorted_Next_Field(form->current));
3185
}
3186
3187
/*---------------------------------------------------------------------------
3188
| Facility : libnform
3189
| Function : static int FN_Sorted_Previous_Field(FORM * form)
3190
|
3191
| Description : Move to the sorted previous field on the current page
3192
| of the form.
3193
|
3194
| Return Values : E_OK - success
3195
| != E_OK - error from subordinate call
3196
+--------------------------------------------------------------------------*/
3197
static int FN_Sorted_Previous_Field(FORM * form)
3198
{
3199
return _nc_Set_Current_Field(form,
3200
Sorted_Previous_Field(form->current));
3201
}
3202
3203
/*---------------------------------------------------------------------------
3204
| Facility : libnform
3205
| Function : static int FN_Sorted_First_Field(FORM * form)
3206
|
3207
| Description : Move to the sorted first field on the current page
3208
| of the form.
3209
|
3210
| Return Values : E_OK - success
3211
| != E_OK - error from subordinate call
3212
+--------------------------------------------------------------------------*/
3213
static int FN_Sorted_First_Field(FORM * form)
3214
{
3215
return _nc_Set_Current_Field(form,
3216
Sorted_Next_Field(form->field[form->page[form->curpage].smax]));
3217
}
3218
3219
/*---------------------------------------------------------------------------
3220
| Facility : libnform
3221
| Function : static int FN_Sorted_Last_Field(FORM * form)
3222
|
3223
| Description : Move to the sorted last field on the current page
3224
| of the form.
3225
|
3226
| Return Values : E_OK - success
3227
| != E_OK - error from subordinate call
3228
+--------------------------------------------------------------------------*/
3229
static int FN_Sorted_Last_Field(FORM * form)
3230
{
3231
return _nc_Set_Current_Field(form,
3232
Sorted_Previous_Field(form->field[form->page[form->curpage].smin]));
3233
}
3234
3235
/*---------------------------------------------------------------------------
3236
| Facility : libnform
3237
| Function : static int FN_Left_Field(FORM * form)
3238
|
3239
| Description : Get the field on the left of the current field on the
3240
| same line and the same page. Cycles through the line.
3241
|
3242
| Return Values : E_OK - success
3243
| != E_OK - error from subordinate call
3244
+--------------------------------------------------------------------------*/
3245
static int FN_Left_Field(FORM * form)
3246
{
3247
return _nc_Set_Current_Field(form,
3248
Left_Neighbour_Field(form->current));
3249
}
3250
3251
/*---------------------------------------------------------------------------
3252
| Facility : libnform
3253
| Function : static int FN_Right_Field(FORM * form)
3254
|
3255
| Description : Get the field on the right of the current field on the
3256
| same line and the same page. Cycles through the line.
3257
|
3258
| Return Values : E_OK - success
3259
| != E_OK - error from subordinate call
3260
+--------------------------------------------------------------------------*/
3261
static int FN_Right_Field(FORM * form)
3262
{
3263
return _nc_Set_Current_Field(form,
3264
Right_Neighbour_Field(form->current));
3265
}
3266
3267
/*---------------------------------------------------------------------------
3268
| Facility : libnform
3269
| Function : static int FN_Up_Field(FORM * form)
3270
|
3271
| Description : Get the upper neighbour of the current field. This
3272
| cycles through the page. See the comments of the
3273
| Upper_Neighbour_Field function to understand how
3274
| 'upper' is defined.
3275
|
3276
| Return Values : E_OK - success
3277
| != E_OK - error from subordinate call
3278
+--------------------------------------------------------------------------*/
3279
static int FN_Up_Field(FORM * form)
3280
{
3281
return _nc_Set_Current_Field(form,
3282
Upper_Neighbour_Field(form->current));
3283
}
3284
3285
/*---------------------------------------------------------------------------
3286
| Facility : libnform
3287
| Function : static int FN_Down_Field(FORM * form)
3288
|
3289
| Description : Get the down neighbour of the current field. This
3290
| cycles through the page. See the comments of the
3291
| Down_Neighbour_Field function to understand how
3292
| 'down' is defined.
3293
|
3294
| Return Values : E_OK - success
3295
| != E_OK - error from subordinate call
3296
+--------------------------------------------------------------------------*/
3297
static int FN_Down_Field(FORM * form)
3298
{
3299
return _nc_Set_Current_Field(form,
3300
Down_Neighbour_Field(form->current));
3301
}
3302
/*----------------------------------------------------------------------------
3303
END of Field Navigation routines
3304
--------------------------------------------------------------------------*/
3305
3306
/*----------------------------------------------------------------------------
3307
Helper routines for Page Navigation
3308
--------------------------------------------------------------------------*/
3309
3310
/*---------------------------------------------------------------------------
3311
| Facility : libnform
3312
| Function : int _nc_Set_Form_Page(FORM * form,
3313
| int page,
3314
| FIELD * field)
3315
|
3316
| Description : Make the given page nr. the current page and make
3317
| the given field the current field on the page. If
3318
| for the field NULL is given, make the first field on
3319
| the page the current field. The routine acts only
3320
| if the requested page is not the current page.
3321
|
3322
| Return Values : E_OK - success
3323
| != E_OK - error from subordinate call
3324
+--------------------------------------------------------------------------*/
3325
int
3326
_nc_Set_Form_Page(FORM * form, int page, FIELD * field)
3327
{
3328
int res = E_OK;
3329
3330
if ((form->curpage!=page))
3331
{
3332
FIELD *last_field, *field_on_page;
3333
3334
werase(Get_Form_Window(form));
3335
form->curpage = page;
3336
last_field = field_on_page = form->field[form->page[page].smin];
3337
do
3338
{
3339
if (field_on_page->opts & O_VISIBLE)
3340
if ((res=Display_Field(field_on_page))!=E_OK)
3341
return(res);
3342
field_on_page = field_on_page->snext;
3343
} while(field_on_page != last_field);
3344
3345
if (field)
3346
res = _nc_Set_Current_Field(form,field);
3347
else
3348
/* N.B.: we don't encapsulate this by Inter_Field_Navigation(),
3349
because this is already executed in a page navigation
3350
context that contains field navigation
3351
*/
3352
res = FN_First_Field(form);
3353
}
3354
return(res);
3355
}
3356
3357
/*---------------------------------------------------------------------------
3358
| Facility : libnform
3359
| Function : static int Next_Page_Number(const FORM * form)
3360
|
3361
| Description : Calculate the page number following the current page
3362
| number. This cycles if the highest page number is
3363
| reached.
3364
|
3365
| Return Values : The next page number
3366
+--------------------------------------------------------------------------*/
3367
INLINE static int Next_Page_Number(const FORM * form)
3368
{
3369
return (form->curpage + 1) % form->maxpage;
3370
}
3371
3372
/*---------------------------------------------------------------------------
3373
| Facility : libnform
3374
| Function : static int Previous_Page_Number(const FORM * form)
3375
|
3376
| Description : Calculate the page number before the current page
3377
| number. This cycles if the first page number is
3378
| reached.
3379
|
3380
| Return Values : The previous page number
3381
+--------------------------------------------------------------------------*/
3382
INLINE static int Previous_Page_Number(const FORM * form)
3383
{
3384
return (form->curpage!=0 ? form->curpage - 1 : form->maxpage - 1);
3385
}
3386
3387
/*----------------------------------------------------------------------------
3388
Page Navigation routines
3389
--------------------------------------------------------------------------*/
3390
3391
/*---------------------------------------------------------------------------
3392
| Facility : libnform
3393
| Function : static int Page_Navigation(
3394
| int (* const fct) (FORM *),
3395
| FORM * form)
3396
|
3397
| Description : Generic behaviour for changing a page. This means
3398
| that the field is left and a new field is entered.
3399
| So the field must be validated and the field init/term
3400
| hooks must be called. Because also the page is changed,
3401
| the forms init/term hooks must be called also.
3402
|
3403
| Return Values : E_OK - success
3404
| E_INVALID_FIELD - field is invalid
3405
| some other - error from subordinate call
3406
+--------------------------------------------------------------------------*/
3407
static int Page_Navigation(int (* const fct) (FORM *), FORM * form)
3408
{
3409
int res;
3410
3411
if (!_nc_Internal_Validation(form))
3412
res = E_INVALID_FIELD;
3413
else
3414
{
3415
Call_Hook(form,fieldterm);
3416
Call_Hook(form,formterm);
3417
res = fct(form);
3418
Call_Hook(form,forminit);
3419
Call_Hook(form,fieldinit);
3420
}
3421
return res;
3422
}
3423
3424
/*---------------------------------------------------------------------------
3425
| Facility : libnform
3426
| Function : static int PN_Next_Page(FORM * form)
3427
|
3428
| Description : Move to the next page of the form
3429
|
3430
| Return Values : E_OK - success
3431
| != E_OK - error from subordinate call
3432
+--------------------------------------------------------------------------*/
3433
static int PN_Next_Page(FORM * form)
3434
{
3435
return _nc_Set_Form_Page(form,Next_Page_Number(form),(FIELD *)0);
3436
}
3437
3438
/*---------------------------------------------------------------------------
3439
| Facility : libnform
3440
| Function : static int PN_Previous_Page(FORM * form)
3441
|
3442
| Description : Move to the previous page of the form
3443
|
3444
| Return Values : E_OK - success
3445
| != E_OK - error from subordinate call
3446
+--------------------------------------------------------------------------*/
3447
static int PN_Previous_Page(FORM * form)
3448
{
3449
return _nc_Set_Form_Page(form,Previous_Page_Number(form),(FIELD *)0);
3450
}
3451
3452
/*---------------------------------------------------------------------------
3453
| Facility : libnform
3454
| Function : static int PN_First_Page(FORM * form)
3455
|
3456
| Description : Move to the first page of the form
3457
|
3458
| Return Values : E_OK - success
3459
| != E_OK - error from subordinate call
3460
+--------------------------------------------------------------------------*/
3461
static int PN_First_Page(FORM * form)
3462
{
3463
return _nc_Set_Form_Page(form,0,(FIELD *)0);
3464
}
3465
3466
/*---------------------------------------------------------------------------
3467
| Facility : libnform
3468
| Function : static int PN_Last_Page(FORM * form)
3469
|
3470
| Description : Move to the last page of the form
3471
|
3472
| Return Values : E_OK - success
3473
| != E_OK - error from subordinate call
3474
+--------------------------------------------------------------------------*/
3475
static int PN_Last_Page(FORM * form)
3476
{
3477
return _nc_Set_Form_Page(form,form->maxpage-1,(FIELD *)0);
3478
}
3479
/*----------------------------------------------------------------------------
3480
END of Field Navigation routines
3481
--------------------------------------------------------------------------*/
3482
3483
/*----------------------------------------------------------------------------
3484
Helper routines for the core form driver.
3485
--------------------------------------------------------------------------*/
3486
3487
/*---------------------------------------------------------------------------
3488
| Facility : libnform
3489
| Function : static int Data_Entry(FORM * form,int c)
3490
|
3491
| Description : Enter character c into at the current position of the
3492
| current field of the form.
3493
|
3494
| Return Values : E_OK -
3495
| E_REQUEST_DENIED -
3496
| E_SYSTEM_ERROR -
3497
+--------------------------------------------------------------------------*/
3498
static int Data_Entry(FORM * form, int c)
3499
{
3500
FIELD *field = form->current;
3501
int result = E_REQUEST_DENIED;
3502
3503
if ( (field->opts & O_EDIT)
3504
#if FIX_FORM_INACTIVE_BUG
3505
&& (field->opts & O_ACTIVE)
3506
#endif
3507
)
3508
{
3509
if ( (field->opts & O_BLANK) &&
3510
First_Position_In_Current_Field(form) &&
3511
!(form->status & _FCHECK_REQUIRED) &&
3512
!(form->status & _WINDOW_MODIFIED) )
3513
werase(form->w);
3514
3515
if (form->status & _OVLMODE)
3516
{
3517
waddch(form->w,(chtype)c);
3518
}
3519
else /* no _OVLMODE */
3520
{
3521
bool There_Is_Room = Is_There_Room_For_A_Char_In_Line(form);
3522
3523
if (!(There_Is_Room ||
3524
((Single_Line_Field(field) && Growable(field)))))
3525
return E_REQUEST_DENIED;
3526
3527
if (!There_Is_Room && !Field_Grown(field,1))
3528
return E_SYSTEM_ERROR;
3529
3530
winsch(form->w,(chtype)c);
3531
}
3532
3533
if ((result=Wrapping_Not_Necessary_Or_Wrapping_Ok(form))==E_OK)
3534
{
3535
bool End_Of_Field= (((field->drows-1)==form->currow) &&
3536
((field->dcols-1)==form->curcol));
3537
form->status |= _WINDOW_MODIFIED;
3538
if (End_Of_Field && !Growable(field) && (field->opts & O_AUTOSKIP))
3539
result = Inter_Field_Navigation(FN_Next_Field,form);
3540
else
3541
{
3542
if (End_Of_Field && Growable(field) && !Field_Grown(field,1))
3543
result = E_SYSTEM_ERROR;
3544
else
3545
{
3546
IFN_Next_Character(form);
3547
result = E_OK;
3548
}
3549
}
3550
}
3551
}
3552
return result;
3553
}
3554
3555
/* Structure to describe the binding of a request code to a function.
3556
The member keycode codes the request value as well as the generic
3557
routine to use for the request. The code for the generic routine
3558
is coded in the upper 16 Bits while the request code is coded in
3559
the lower 16 bits.
3560
3561
In terms of C++ you might think of a request as a class with a
3562
virtual method "perform". The different types of request are
3563
derived from this base class and overload (or not) the base class
3564
implementation of perform.
3565
*/
3566
typedef struct {
3567
int keycode; /* must be at least 32 bit: hi:mode, lo: key */
3568
int (*cmd)(FORM *); /* low level driver routine for this key */
3569
} Binding_Info;
3570
3571
/* You may see this is the class-id of the request type class */
3572
#define ID_PN (0x00000000) /* Page navigation */
3573
#define ID_FN (0x00010000) /* Inter-Field navigation */
3574
#define ID_IFN (0x00020000) /* Intra-Field navigation */
3575
#define ID_VSC (0x00030000) /* Vertical Scrolling */
3576
#define ID_HSC (0x00040000) /* Horizontal Scrolling */
3577
#define ID_FE (0x00050000) /* Field Editing */
3578
#define ID_EM (0x00060000) /* Edit Mode */
3579
#define ID_FV (0x00070000) /* Field Validation */
3580
#define ID_CH (0x00080000) /* Choice */
3581
#define ID_Mask (0xffff0000)
3582
#define Key_Mask (0x0000ffff)
3583
#define ID_Shft (16)
3584
3585
/* This array holds all the Binding Infos */
3586
static const Binding_Info bindings[MAX_FORM_COMMAND - MIN_FORM_COMMAND + 1] =
3587
{
3588
{ REQ_NEXT_PAGE |ID_PN ,PN_Next_Page},
3589
{ REQ_PREV_PAGE |ID_PN ,PN_Previous_Page},
3590
{ REQ_FIRST_PAGE |ID_PN ,PN_First_Page},
3591
{ REQ_LAST_PAGE |ID_PN ,PN_Last_Page},
3592
3593
{ REQ_NEXT_FIELD |ID_FN ,FN_Next_Field},
3594
{ REQ_PREV_FIELD |ID_FN ,FN_Previous_Field},
3595
{ REQ_FIRST_FIELD |ID_FN ,FN_First_Field},
3596
{ REQ_LAST_FIELD |ID_FN ,FN_Last_Field},
3597
{ REQ_SNEXT_FIELD |ID_FN ,FN_Sorted_Next_Field},
3598
{ REQ_SPREV_FIELD |ID_FN ,FN_Sorted_Previous_Field},
3599
{ REQ_SFIRST_FIELD |ID_FN ,FN_Sorted_First_Field},
3600
{ REQ_SLAST_FIELD |ID_FN ,FN_Sorted_Last_Field},
3601
{ REQ_LEFT_FIELD |ID_FN ,FN_Left_Field},
3602
{ REQ_RIGHT_FIELD |ID_FN ,FN_Right_Field},
3603
{ REQ_UP_FIELD |ID_FN ,FN_Up_Field},
3604
{ REQ_DOWN_FIELD |ID_FN ,FN_Down_Field},
3605
3606
{ REQ_NEXT_CHAR |ID_IFN ,IFN_Next_Character},
3607
{ REQ_PREV_CHAR |ID_IFN ,IFN_Previous_Character},
3608
{ REQ_NEXT_LINE |ID_IFN ,IFN_Next_Line},
3609
{ REQ_PREV_LINE |ID_IFN ,IFN_Previous_Line},
3610
{ REQ_NEXT_WORD |ID_IFN ,IFN_Next_Word},
3611
{ REQ_PREV_WORD |ID_IFN ,IFN_Previous_Word},
3612
{ REQ_BEG_FIELD |ID_IFN ,IFN_Beginning_Of_Field},
3613
{ REQ_END_FIELD |ID_IFN ,IFN_End_Of_Field},
3614
{ REQ_BEG_LINE |ID_IFN ,IFN_Beginning_Of_Line},
3615
{ REQ_END_LINE |ID_IFN ,IFN_End_Of_Line},
3616
{ REQ_LEFT_CHAR |ID_IFN ,IFN_Left_Character},
3617
{ REQ_RIGHT_CHAR |ID_IFN ,IFN_Right_Character},
3618
{ REQ_UP_CHAR |ID_IFN ,IFN_Up_Character},
3619
{ REQ_DOWN_CHAR |ID_IFN ,IFN_Down_Character},
3620
3621
{ REQ_NEW_LINE |ID_FE ,FE_New_Line},
3622
{ REQ_INS_CHAR |ID_FE ,FE_Insert_Character},
3623
{ REQ_INS_LINE |ID_FE ,FE_Insert_Line},
3624
{ REQ_DEL_CHAR |ID_FE ,FE_Delete_Character},
3625
{ REQ_DEL_PREV |ID_FE ,FE_Delete_Previous},
3626
{ REQ_DEL_LINE |ID_FE ,FE_Delete_Line},
3627
{ REQ_DEL_WORD |ID_FE ,FE_Delete_Word},
3628
{ REQ_CLR_EOL |ID_FE ,FE_Clear_To_End_Of_Line},
3629
{ REQ_CLR_EOF |ID_FE ,FE_Clear_To_End_Of_Form},
3630
{ REQ_CLR_FIELD |ID_FE ,FE_Clear_Field},
3631
3632
{ REQ_OVL_MODE |ID_EM ,EM_Overlay_Mode},
3633
{ REQ_INS_MODE |ID_EM ,EM_Insert_Mode},
3634
3635
{ REQ_SCR_FLINE |ID_VSC ,VSC_Scroll_Line_Forward},
3636
{ REQ_SCR_BLINE |ID_VSC ,VSC_Scroll_Line_Backward},
3637
{ REQ_SCR_FPAGE |ID_VSC ,VSC_Scroll_Page_Forward},
3638
{ REQ_SCR_BPAGE |ID_VSC ,VSC_Scroll_Page_Backward},
3639
{ REQ_SCR_FHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Forward},
3640
{ REQ_SCR_BHPAGE |ID_VSC ,VSC_Scroll_Half_Page_Backward},
3641
3642
{ REQ_SCR_FCHAR |ID_HSC ,HSC_Scroll_Char_Forward},
3643
{ REQ_SCR_BCHAR |ID_HSC ,HSC_Scroll_Char_Backward},
3644
{ REQ_SCR_HFLINE |ID_HSC ,HSC_Horizontal_Line_Forward},
3645
{ REQ_SCR_HBLINE |ID_HSC ,HSC_Horizontal_Line_Backward},
3646
{ REQ_SCR_HFHALF |ID_HSC ,HSC_Horizontal_Half_Line_Forward},
3647
{ REQ_SCR_HBHALF |ID_HSC ,HSC_Horizontal_Half_Line_Backward},
3648
3649
{ REQ_VALIDATION |ID_FV ,FV_Validation},
3650
3651
{ REQ_NEXT_CHOICE |ID_CH ,CR_Next_Choice},
3652
{ REQ_PREV_CHOICE |ID_CH ,CR_Previous_Choice}
3653
};
3654
3655
/*---------------------------------------------------------------------------
3656
| Facility : libnform
3657
| Function : int form_driver(FORM * form,int c)
3658
|
3659
| Description : This is the workhorse of the forms system. It checks
3660
| to determine whether the character c is a request or
3661
| data. If it is a request, the form driver executes
3662
| the request and returns the result. If it is data
3663
| (printable character), it enters the data into the
3664
| current position in the current field. If it is not
3665
| recognized, the form driver assumes it is an application
3666
| defined command and returns E_UNKNOWN_COMMAND.
3667
| Application defined command should be defined relative
3668
| to MAX_FORM_COMMAND, the maximum value of a request.
3669
|
3670
| Return Values : E_OK - success
3671
| E_SYSTEM_ERROR - system error
3672
| E_BAD_ARGUMENT - an argument is incorrect
3673
| E_NOT_POSTED - form is not posted
3674
| E_INVALID_FIELD - field contents are invalid
3675
| E_BAD_STATE - called from inside a hook routine
3676
| E_REQUEST_DENIED - request failed
3677
| E_UNKNOWN_COMMAND - command not known
3678
+--------------------------------------------------------------------------*/
3679
int form_driver(FORM * form, int c)
3680
{
3681
const Binding_Info* BI = (Binding_Info *)0;
3682
int res = E_UNKNOWN_COMMAND;
3683
3684
if (!form)
3685
RETURN(E_BAD_ARGUMENT);
3686
3687
if (!(form->field))
3688
RETURN(E_NOT_CONNECTED);
3689
3690
assert(form->page != 0);
3691
3692
if (c==FIRST_ACTIVE_MAGIC)
3693
{
3694
form->current = _nc_First_Active_Field(form);
3695
return E_OK;
3696
}
3697
3698
assert(form->current &&
3699
form->current->buf &&
3700
(form->current->form == form)
3701
);
3702
3703
if ( form->status & _IN_DRIVER )
3704
RETURN(E_BAD_STATE);
3705
3706
if ( !( form->status & _POSTED ) )
3707
RETURN(E_NOT_POSTED);
3708
3709
if ((c>=MIN_FORM_COMMAND && c<=MAX_FORM_COMMAND) &&
3710
((bindings[c-MIN_FORM_COMMAND].keycode & Key_Mask) == c))
3711
BI = &(bindings[c-MIN_FORM_COMMAND]);
3712
3713
if (BI)
3714
{
3715
typedef int (*Generic_Method)(int (* const)(FORM *),FORM *);
3716
static const Generic_Method Generic_Methods[] =
3717
{
3718
Page_Navigation, /* overloaded to call field&form hooks */
3719
Inter_Field_Navigation, /* overloaded to call field hooks */
3720
NULL, /* Intra-Field is generic */
3721
Vertical_Scrolling, /* Overloaded to check multi-line */
3722
Horizontal_Scrolling, /* Overloaded to check single-line */
3723
Field_Editing, /* Overloaded to mark modification */
3724
NULL, /* Edit Mode is generic */
3725
NULL, /* Field Validation is generic */
3726
NULL /* Choice Request is generic */
3727
};
3728
size_t nMethods = (sizeof(Generic_Methods)/sizeof(Generic_Methods[0]));
3729
size_t method = ((BI->keycode & ID_Mask) >> ID_Shft) & 0xffff;
3730
3731
if ( (method >= nMethods) || !(BI->cmd) )
3732
res = E_SYSTEM_ERROR;
3733
else
3734
{
3735
Generic_Method fct = Generic_Methods[method];
3736
if (fct)
3737
res = fct(BI->cmd,form);
3738
else
3739
res = (BI->cmd)(form);
3740
}
3741
}
3742
else
3743
{
3744
if (!(c & (~(int)MAX_REGULAR_CHARACTER)) &&
3745
isprint((unsigned char)c) &&
3746
Check_Char(form->current->type,c,
3747
(TypeArgument *)(form->current->arg)))
3748
res = Data_Entry(form,c);
3749
}
3750
_nc_Refresh_Current_Field(form);
3751
RETURN(res);
3752
}
3753
3754
/*----------------------------------------------------------------------------
3755
Field-Buffer manipulation routines.
3756
The effects of setting a buffer is tightly coupled to the core of the form
3757
driver logic. This is especially true in the case of growable fields.
3758
So I don't separate this into an own module.
3759
--------------------------------------------------------------------------*/
3760
3761
/*---------------------------------------------------------------------------
3762
| Facility : libnform
3763
| Function : int set_field_buffer(FIELD *field,
3764
| int buffer, char *value)
3765
|
3766
| Description : Set the given buffer of the field to the given value.
3767
| Buffer 0 stores the displayed content of the field.
3768
| For dynamic fields this may grow the fieldbuffers if
3769
| the length of the value exceeds the current buffer
3770
| length. For buffer 0 only printable values are allowed.
3771
| For static fields, the value needs not to be zero ter-
3772
| minated. It is copied up to the length of the buffer.
3773
|
3774
| Return Values : E_OK - success
3775
| E_BAD_ARGUMENT - invalid argument
3776
| E_SYSTEM_ERROR - system error
3777
+--------------------------------------------------------------------------*/
3778
int set_field_buffer(FIELD * field, int buffer, const char * value)
3779
{
3780
char *s, *p;
3781
int res = E_OK;
3782
unsigned int len;
3783
3784
if ( !field || !value || ((buffer < 0)||(buffer > field->nbuf)) )
3785
RETURN(E_BAD_ARGUMENT);
3786
3787
len = Buffer_Length(field);
3788
3789
if (buffer==0)
3790
{
3791
const char *v;
3792
unsigned int i = 0;
3793
3794
for(v=value; *v && (i<len); v++,i++)
3795
{
3796
if (!isprint((unsigned char)*v))
3797
RETURN(E_BAD_ARGUMENT);
3798
}
3799
}
3800
3801
if (Growable(field))
3802
{
3803
/* for a growable field we must assume zero terminated strings, because
3804
somehow we have to detect the length of what should be copied.
3805
*/
3806
unsigned int vlen = strlen(value);
3807
if (vlen > len)
3808
{
3809
if (!Field_Grown(field,
3810
(int)(1 + (vlen-len)/((field->rows+field->nrow)*field->cols))))
3811
RETURN(E_SYSTEM_ERROR);
3812
3813
/* in this case we also have to check, whether or not the remaining
3814
characters in value are also printable for buffer 0. */
3815
if (buffer==0)
3816
{
3817
unsigned int i;
3818
3819
for(i=len; i<vlen; i++)
3820
if (!isprint((int)(value[i])))
3821
RETURN(E_BAD_ARGUMENT);
3822
}
3823
len = vlen;
3824
}
3825
}
3826
3827
p = Address_Of_Nth_Buffer(field,buffer);
3828
3829
#if HAVE_MEMCCPY
3830
s = memccpy(p,value,0,len);
3831
#else
3832
for(s=(char *)value; *s && (s < (value+len)); s++)
3833
p[s-value] = *s;
3834
if (s < (value+len))
3835
{
3836
int off = s-value;
3837
p[off] = *s++;
3838
s = p + (s-value);
3839
}
3840
else
3841
s=(char *)0;
3842
#endif
3843
3844
if (s)
3845
{ /* this means, value was null terminated and not greater than the
3846
buffer. We have to pad with blanks. Please note that due to memccpy
3847
logic s points after the terminating null. */
3848
s--; /* now we point to the terminator. */
3849
assert(len >= (unsigned int)(s-p));
3850
if (len > (unsigned int)(s-p))
3851
memset(s,C_BLANK,len-(unsigned int)(s-p));
3852
}
3853
3854
if (buffer==0)
3855
{
3856
int syncres;
3857
if (((syncres=Synchronize_Field( field ))!=E_OK) &&
3858
(res==E_OK))
3859
res = syncres;
3860
if (((syncres=Synchronize_Linked_Fields(field ))!=E_OK) &&
3861
(res==E_OK))
3862
res = syncres;
3863
}
3864
RETURN(res);
3865
}
3866
3867
/*---------------------------------------------------------------------------
3868
| Facility : libnform
3869
| Function : char *field_buffer(const FIELD *field,int buffer)
3870
|
3871
| Description : Return the address of the buffer for the field.
3872
|
3873
| Return Values : Pointer to buffer or NULL if arguments were invalid.
3874
+--------------------------------------------------------------------------*/
3875
char *field_buffer(const FIELD * field, int buffer)
3876
{
3877
if (field && (buffer >= 0) && (buffer <= field->nbuf))
3878
return Address_Of_Nth_Buffer(field,buffer);
3879
else
3880
return (char *)0;
3881
}
3882
3883
/* frm_driver.c ends here */
3884
3885