9b88ee3f35832b0ffbfd23add3f391c7aa3e46df
[ncurses.git] / form / fld_def.c
1 /*-----------------------------------------------------------------------------+
2 |           The ncurses form library is  Copyright (C) 1995-1997               |
3 |             by Juergen Pfeifer <Juergen.Pfeifer@T-Online.de>                 |
4 |                          All Rights Reserved.                                |
5 |                                                                              |
6 | Permission to use, copy, modify, and distribute this software and its        |
7 | documentation for any purpose and without fee is hereby granted, provided    |
8 | that the above copyright notice appear in all copies and that both that      |
9 | copyright notice and this permission notice appear in supporting             |
10 | documentation, and that the name of the above listed copyright holder(s) not |
11 | be used in advertising or publicity pertaining to distribution of the        |
12 | software without specific, written prior permission.                         | 
13 |                                                                              |
14 | THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO  |
15 | THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-  |
16 | NESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR   |
17 | ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RE- |
18 | SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
19 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH    |
20 | THE USE OR PERFORMANCE OF THIS SOFTWARE.                                     |
21 +-----------------------------------------------------------------------------*/
22
23 #include "form.priv.h"
24
25 MODULE_ID("$Id: fld_def.c,v 1.6 1997/05/01 16:47:54 juergen Exp $")
26
27 /* this can't be readonly */
28 static FIELD default_field = {
29   0,                       /* status */
30   0,                       /* rows   */
31   0,                       /* cols   */
32   0,                       /* frow   */
33   0,                       /* fcol   */
34   0,                       /* drows  */
35   0,                       /* dcols  */
36   0,                       /* maxgrow*/
37   0,                       /* nrow   */
38   0,                       /* nbuf   */
39   NO_JUSTIFICATION,        /* just   */
40   0,                       /* page   */
41   0,                       /* index  */
42   (int)' ',                /* pad    */
43   A_NORMAL,                /* fore   */
44   A_NORMAL,                /* back   */
45   ALL_FIELD_OPTS,          /* opts   */
46   (FIELD *)0,              /* snext  */
47   (FIELD *)0,              /* sprev  */
48   (FIELD *)0,              /* link   */
49   (FORM *)0,               /* form   */
50   (FIELDTYPE *)0,          /* type   */
51   (char *)0,               /* arg    */ 
52   (char *)0,               /* buf    */
53   (char *)0                /* usrptr */
54 };
55
56 FIELD *_nc_Default_Field = &default_field;
57 \f
58 /*---------------------------------------------------------------------------
59 |   Facility      :  libnform  
60 |   Function      :  static TypeArgument *Make_Argument(
61 |                              const FIELDTYPE *typ,
62 |                              va_list *ap,
63 |                              int *err )
64 |   
65 |   Description   :  Create an argument structure for the specified type.
66 |                    Use the type-dependant argument list to construct
67 |                    it.
68 |
69 |   Return Values :  Pointer to argument structure. Maybe NULL.
70 |                    In case of an error in *err an errorcounter is increased. 
71 +--------------------------------------------------------------------------*/
72 static TypeArgument* Make_Argument(const FIELDTYPE *typ, va_list *ap, int *err)
73 {
74   TypeArgument *res = (TypeArgument *)0; 
75   TypeArgument *p;
76
77   if (typ && (typ->status & _HAS_ARGS))
78     {
79       assert(err && ap);
80       if (typ->status & _LINKED_TYPE)
81         {
82           p = (TypeArgument *)malloc(sizeof(TypeArgument));
83           if (p) 
84             {
85               p->left  = Make_Argument(typ->left ,ap,err);
86               p->right = Make_Argument(typ->right,ap,err);
87               return p;
88             }
89           else
90             *err += 1;
91       } else 
92         {
93           if ( !(res=(TypeArgument *)typ->makearg(ap)) ) 
94             *err += 1;
95         }
96     }
97   return res;
98 }
99
100 /*---------------------------------------------------------------------------
101 |   Facility      :  libnform  
102 |   Function      :  static TypeArgument *Copy_Argument(
103 |                              const FIELDTYPE *typ,
104 |                              const TypeArgument *argp,
105 |                              int *err )
106 |   
107 |   Description   :  Create a copy of an argument structure for the specified 
108 |                    type.
109 |
110 |   Return Values :  Pointer to argument structure. Maybe NULL.
111 |                    In case of an error in *err an errorcounter is increased. 
112 +--------------------------------------------------------------------------*/
113 static TypeArgument *Copy_Argument(const FIELDTYPE *typ,
114                                    const TypeArgument *argp, int *err)
115 {
116   TypeArgument *res = (TypeArgument *)0;
117   TypeArgument *p;
118
119   if ( typ && (typ->status & _HAS_ARGS) )
120     {
121       assert(err && argp);
122       if (typ->status & _LINKED_TYPE)
123         {
124           p = (TypeArgument *)malloc(sizeof(TypeArgument));
125           if (p)
126             {
127               p->left  = Copy_Argument(typ,argp->left ,err);
128               p->right = Copy_Argument(typ,argp->right,err);
129               return p;
130             }
131           *err += 1;
132       } 
133       else 
134         {
135           if (!(res = (TypeArgument *)(typ->copyarg((const void *)argp)))) 
136             *err += 1;
137         }
138     }
139   return res;
140 }
141
142 /*---------------------------------------------------------------------------
143 |   Facility      :  libnform  
144 |   Function      :  static void Free_Argument(
145 |                                  const FIELDTYPE *typ,
146 |                                  TypeArgument * argp )
147 |   
148 |   Description   :  Release memory associated with the argument structure
149 |                    for the given fieldtype.
150 |
151 |   Return Values :  -
152 +--------------------------------------------------------------------------*/
153 static void Free_Argument(const FIELDTYPE * typ, TypeArgument * argp)
154 {
155   if (!typ || !(typ->status & _HAS_ARGS)) 
156     return;
157   
158   if (typ->status & _LINKED_TYPE)
159     {
160       assert(argp);
161       Free_Argument(typ->left ,argp->left );
162       Free_Argument(typ->right,argp->right);
163       free(argp);
164     } 
165   else 
166     {
167       typ->freearg((void *)argp);
168     }
169 }
170
171 /*---------------------------------------------------------------------------
172 |   Facility      :  libnform  
173 |   Function      :  static bool Copy_Type( FIELD *new, FIELD const *old )
174 |   
175 |   Description   :  Copy argument structure of field old to field new
176 |
177 |   Return Values :  TRUE       - copy worked
178 |                    FALSE      - error occured
179 +--------------------------------------------------------------------------*/
180 static bool Copy_Type(FIELD *new, FIELD const *old)
181 {
182   int err = 0;
183
184   assert(new && old);
185
186   new->type = old->type;
187   new->arg  = (void *)Copy_Argument(old->type,(TypeArgument *)(old->arg),&err);
188
189   if (err)
190     {
191       Free_Argument(new->type,(TypeArgument *)(new->arg));
192       new->type = (FIELDTYPE *)0;
193       new->arg  = (void *)0;
194       return FALSE;
195     }
196   else
197     {
198       if (new->type) 
199         new->type->ref++;
200       return TRUE;
201     }
202 }
203
204 /*---------------------------------------------------------------------------
205 |   Facility      :  libnform  
206 |   Function      :  static void Free_Type( FIELD *field )
207 |   
208 |   Description   :  Release Argument structure for this field
209 |
210 |   Return Values :  -
211 +--------------------------------------------------------------------------*/
212 INLINE static void Free_Type(FIELD *field)
213 {
214   assert(field);
215   if (field->type) 
216     field->type->ref--;
217   Free_Argument(field->type,(TypeArgument *)(field->arg));
218 }
219
220 /*---------------------------------------------------------------------------
221 |   Facility      :  libnform  
222 |   Function      :  FIELD *new_field( int rows, int cols, 
223 |                                      int frow, int fcol,
224 |                                      int nrow, int nbuf )
225 |   
226 |   Description   :  Create a new field with this many 'rows' and 'cols',
227 |                    starting at 'frow/fcol' in the subwindow of the form.
228 |                    Allocate 'nrow' off-screen rows and 'nbuf' additional
229 |                    buffers. If an error occurs, errno is set to
230 |                    
231 |                    E_BAD_ARGUMENT - invalid argument
232 |                    E_SYSTEM_ERROR - system error
233 |
234 |   Return Values :  Pointer to the new field or NULL if failure.
235 +--------------------------------------------------------------------------*/
236 FIELD *new_field(int rows, int cols, int frow, int fcol, int nrow, int nbuf)
237 {
238   FIELD *New_Field = (FIELD *)0;
239   int err = E_BAD_ARGUMENT;
240
241   if (rows>0  && 
242       cols>0  && 
243       frow>=0 && 
244       fcol>=0 && 
245       nrow>=0 && 
246       nbuf>=0 &&
247       ((err = E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */
248       (New_Field=(FIELD *)malloc(sizeof(FIELD))) )
249     {
250       *New_Field       = default_field;
251       New_Field->rows  = rows;
252       New_Field->cols  = cols;
253       New_Field->drows = rows + nrow;
254       New_Field->dcols = cols;
255       New_Field->frow  = frow;
256       New_Field->fcol  = fcol;
257       New_Field->nrow  = nrow;
258       New_Field->nbuf  = nbuf;
259       New_Field->link  = New_Field;
260
261       if (Copy_Type(New_Field,&default_field))
262         {
263           size_t len;
264
265           len = Total_Buffer_Size(New_Field);
266           if ((New_Field->buf = (char *)malloc(len)))
267             {
268               /* Prefill buffers with blanks and insert terminating zeroes
269                  between buffers */
270               int i;
271
272               memset(New_Field->buf,' ',len);
273               for(i=0;i<=New_Field->nbuf;i++)
274                 {
275                   New_Field->buf[(New_Field->drows*New_Field->cols+1)*(i+1)-1]
276                     = '\0';
277                 }
278               return New_Field;
279             }
280         }
281     }
282
283   if (New_Field) 
284     free_field(New_Field);
285   
286   SET_ERROR( err );
287   return (FIELD *)0;
288 }
289
290 /*---------------------------------------------------------------------------
291 |   Facility      :  libnform  
292 |   Function      :  FIELD *dup_field(FIELD *field, int frow, int fcol)
293 |   
294 |   Description   :  Duplicates the field at the specified position. All
295 |                    field attributes and the buffers are copied.
296 |                    If an error occurs, errno is set to
297 |                    
298 |                    E_BAD_ARGUMENT - invalid argument
299 |                    E_SYSTEM_ERROR - system error
300 |
301 |   Return Values :  Pointer to the new field or NULL if failure
302 +--------------------------------------------------------------------------*/
303 FIELD *dup_field(FIELD * field, int frow, int fcol)
304 {
305   FIELD *New_Field = (FIELD *)0;
306   int err = E_BAD_ARGUMENT;
307
308   if (field && (frow>=0) && (fcol>=0) && 
309       ((err=E_SYSTEM_ERROR) != 0) && /* trick : this resets the default error */
310       (New_Field=(FIELD *)malloc(sizeof(FIELD))) )
311     {
312       *New_Field         = default_field;
313       New_Field->frow    = frow;
314       New_Field->fcol    = fcol;
315       New_Field->link    = New_Field;
316       New_Field->rows    = field->rows;
317       New_Field->cols    = field->cols;
318       New_Field->nrow    = field->nrow;
319       New_Field->drows   = field->drows;
320       New_Field->dcols   = field->dcols;
321       New_Field->maxgrow = field->maxgrow;
322       New_Field->nbuf    = field->nbuf;
323       New_Field->just    = field->just;
324       New_Field->fore    = field->fore;
325       New_Field->back    = field->back;
326       New_Field->pad     = field->pad;
327       New_Field->opts    = field->opts;
328       New_Field->usrptr  = field->usrptr;
329
330       if (Copy_Type(New_Field,field))
331         {
332           size_t len;
333
334           len = Total_Buffer_Size(New_Field);
335           if ( (New_Field->buf=(char *)malloc(len)) )
336             {
337               memcpy(New_Field->buf,field->buf,len);
338               return New_Field;
339             }
340         }
341     }
342
343   if (New_Field) 
344     free_field(New_Field);
345
346   SET_ERROR(err);
347   return (FIELD *)0;
348 }
349
350 /*---------------------------------------------------------------------------
351 |   Facility      :  libnform  
352 |   Function      :  FIELD *link_field(FIELD *field, int frow, int fcol)  
353 |   
354 |   Description   :  Duplicates the field at the specified position. The
355 |                    new field shares its buffers with the original one,
356 |                    the attributes are independent.
357 |                    If an error occurs, errno is set to
358 |                    
359 |                    E_BAD_ARGUMENT - invalid argument
360 |                    E_SYSTEM_ERROR - system error
361 |
362 |   Return Values :  Pointer to the new field or NULL if failure
363 +--------------------------------------------------------------------------*/
364 FIELD *link_field(FIELD * field, int frow, int fcol)
365 {
366   FIELD *New_Field = (FIELD *)0;
367   int err = E_BAD_ARGUMENT;
368
369   if (field && (frow>=0) && (fcol>=0) &&
370       ((err=E_SYSTEM_ERROR) != 0) && /* trick: this resets the default error */
371       (New_Field = (FIELD *)malloc(sizeof(FIELD))) )
372     {
373       *New_Field        = default_field;
374       New_Field->frow   = frow;
375       New_Field->fcol   = fcol;
376       New_Field->link   = field->link;
377       field->link       = New_Field;
378       New_Field->buf    = field->buf;
379       New_Field->rows   = field->rows;
380       New_Field->cols   = field->cols;
381       New_Field->nrow   = field->nrow;
382       New_Field->nbuf   = field->nbuf;
383       New_Field->drows  = field->drows;
384       New_Field->dcols  = field->dcols;
385       New_Field->maxgrow= field->maxgrow;
386       New_Field->just   = field->just;
387       New_Field->fore   = field->fore;
388       New_Field->back   = field->back;
389       New_Field->pad    = field->pad;
390       New_Field->opts   = field->opts;
391       New_Field->usrptr = field->usrptr;
392       if (Copy_Type(New_Field,field)) 
393         return New_Field;
394     }
395
396   if (New_Field) 
397     free_field(New_Field);
398
399   SET_ERROR( err );
400   return (FIELD *)0;
401 }
402
403 /*---------------------------------------------------------------------------
404 |   Facility      :  libnform  
405 |   Function      :  int free_field( FIELD *field )
406 |   
407 |   Description   :  Frees the storage allocated for the field.
408 |
409 |   Return Values :  E_OK           - success
410 |                    E_BAD_ARGUMENT - invalid field pointer
411 |                    E_CONNECTED    - field is connected
412 +--------------------------------------------------------------------------*/
413 int free_field(FIELD * field)
414 {
415   if (!field) 
416     RETURN(E_BAD_ARGUMENT);
417
418   if (field->form)
419     RETURN(E_CONNECTED);
420   
421   if (field == field->link)
422     {
423       if (field->buf) 
424         free(field->buf);
425     }
426   else 
427     {
428       FIELD *f;
429
430       for(f=field;f->link != field;f = f->link) 
431         {}
432       f->link = field->link;
433     }
434   Free_Type(field);
435   free(field);
436   RETURN(E_OK);
437 }
438
439 /*---------------------------------------------------------------------------
440 |   Facility      :  libnform  
441 |   Function      :  int field_info(const FIELD *field,
442 |                                   int *rows, int *cols,
443 |                                   int *frow, int *fcol,
444 |                                   int *nrow, int *nbuf)
445 |   
446 |   Description   :  Retrieve infos about the fields creation parameters.
447 |
448 |   Return Values :  E_OK           - success
449 |                    E_BAD_ARGUMENT - invalid field pointer
450 +--------------------------------------------------------------------------*/
451 int field_info(const FIELD *field,
452                int *rows, int *cols, 
453                int *frow, int *fcol, 
454                int *nrow, int *nbuf)
455 {
456   if (!field) 
457     RETURN(E_BAD_ARGUMENT);
458
459   if (rows) *rows = field->rows;
460   if (cols) *cols = field->cols;
461   if (frow) *frow = field->frow;
462   if (fcol) *fcol = field->fcol;
463   if (nrow) *nrow = field->nrow;
464   if (nbuf) *nbuf = field->nbuf;
465   RETURN(E_OK);
466 }
467         
468 /*---------------------------------------------------------------------------
469 |   Facility      :  libnform  
470 |   Function      :  int move_field(FIELD *field,int frow, int fcol)
471 |   
472 |   Description   :  Moves the disconnected field to the new location in
473 |                    the forms subwindow.
474 |
475 |   Return Values :  E_OK            - success
476 |                    E_BAD_ARGUMENT  - invalid argument passed
477 |                    E_CONNECTED     - field is connected
478 +--------------------------------------------------------------------------*/
479 int move_field(FIELD *field, int frow, int fcol)
480 {
481   if ( !field || (frow<0) || (fcol<0) ) 
482     RETURN(E_BAD_ARGUMENT);
483
484   if (field->form) 
485     RETURN(E_CONNECTED);
486
487   field->frow = frow;
488   field->fcol = fcol;
489   RETURN(E_OK);
490 }
491
492 /*---------------------------------------------------------------------------
493 |   Facility      :  libnform  
494 |   Function      :  int set_field_type(FIELD *field, FIELDTYPE *type,...)
495 |   
496 |   Description   :  Associate the specified fieldtype with the field.
497 |                    Certain field types take additional arguments. Look
498 |                    at the spec of the field types !
499 |
500 |   Return Values :  E_OK           - success
501 |                    E_SYSTEM_ERROR - system error
502 +--------------------------------------------------------------------------*/
503 int set_field_type(FIELD *field,FIELDTYPE *type, ...)
504 {
505   va_list ap;
506   int res = E_SYSTEM_ERROR;
507   int err = 0;
508
509   va_start(ap,type);
510
511   Normalize_Field(field);
512   Free_Type(field);
513
514   field->type = type;
515   field->arg  = (void *)Make_Argument(field->type,&ap,&err);
516
517   if (err)
518     {
519       Free_Argument(field->type,(TypeArgument *)(field->arg));
520       field->type = (FIELDTYPE *)0;
521       field->arg  = (void *)0;
522     }
523   else
524     {
525       res = E_OK;
526       if (field->type) 
527         field->type->ref++;
528     }
529
530   va_end(ap);
531   RETURN(res);
532 }
533
534 /*---------------------------------------------------------------------------
535 |   Facility      :  libnform  
536 |   Function      :  FIELDTYPE *field_type(const FIELD *field)
537 |   
538 |   Description   :  Retrieve the associated fieldtype for this field.
539 |
540 |   Return Values :  Pointer to fieldtype of NULL if none is defined.
541 +--------------------------------------------------------------------------*/
542 FIELDTYPE *field_type(const FIELD * field)
543 {
544   return Normalize_Field(field)->type;
545 }
546
547 /*---------------------------------------------------------------------------
548 |   Facility      :  libnform  
549 |   Function      :  void *field_arg(const FIELD *field)
550 |   
551 |   Description   :  Retrieve pointer to the fields argument structure.
552 |
553 |   Return Values :  Pointer to structure or NULL if none is defined.
554 +--------------------------------------------------------------------------*/
555 void *field_arg(const FIELD * field)
556 {
557   return Normalize_Field(field)->arg;
558 }
559
560 /*---------------------------------------------------------------------------
561 |   Facility      :  libnform  
562 |   Function      :  int set_max_field(FIELD *field, int maxgrow)
563 |   
564 |   Description   :  Set the maximum growth for a dynamic field. If maxgrow=0
565 |                    the field may grow to any possible size.
566 |
567 |   Return Values :  E_OK           - success
568 |                    E_BAD_ARGUMENT - invalid argument
569 +--------------------------------------------------------------------------*/
570 int set_max_field(FIELD *field, int maxgrow)
571 {
572   if (!field || (maxgrow<0))
573     RETURN(E_BAD_ARGUMENT);
574   else
575     {
576       bool single_line_field = Single_Line_Field(field);
577
578       if (maxgrow>0)
579         {
580           if (( single_line_field && (maxgrow < field->dcols)) ||
581               (!single_line_field && (maxgrow < field->drows)))
582             RETURN(E_BAD_ARGUMENT);
583         }
584       field->maxgrow = maxgrow;
585       field->status &= ~_MAY_GROW;
586       if (!(field->opts & O_STATIC))
587         {
588           if ((maxgrow==0) ||
589               ( single_line_field && (field->dcols < maxgrow)) ||
590               (!single_line_field && (field->drows < maxgrow)))
591             field->status |= _MAY_GROW;
592         }
593     }
594   RETURN(E_OK);
595 }
596                   
597 /*---------------------------------------------------------------------------
598 |   Facility      :  libnform  
599 |   Function      :  int dynamic_field_info(const FIELD *field,
600 |                                           int *drows, int *dcols,
601 |                                           int *maxgrow)
602 |   
603 |   Description   :  Retrieve informations about a dynamic fields current
604 |                    dynamic parameters.
605 |
606 |   Return Values :  E_OK           - success
607 |                    E_BAD_ARGUMENT - invalid argument
608 +--------------------------------------------------------------------------*/
609 int dynamic_field_info(const FIELD *field,
610                        int *drows, int *dcols, int *maxgrow)
611 {
612   if (!field)
613     RETURN(E_BAD_ARGUMENT);
614
615   if (drows)   *drows   = field->drows;
616   if (dcols)   *dcols   = field->dcols;
617   if (maxgrow) *maxgrow = field->maxgrow;
618
619   RETURN(E_OK);
620 }
621
622 /*---------------------------------------------------------------------------
623 |   Facility      :  libnform  
624 |   Function      :  int set_new_page(FIELD *field, bool new_page_flag)
625 |   
626 |   Description   :  Marks the field as the beginning of a new page of 
627 |                    the form.
628 |
629 |   Return Values :  E_OK         - success
630 |                    E_CONNECTED  - field is connected
631 +--------------------------------------------------------------------------*/
632 int set_new_page(FIELD * field, bool new_page_flag)
633 {
634   Normalize_Field(field);
635   if (field->form) 
636     RETURN(E_CONNECTED);
637
638   if (new_page_flag) 
639     field->status |= _NEWPAGE;
640   else
641     field->status &= ~_NEWPAGE;
642
643   RETURN(E_OK);
644 }
645
646 /*---------------------------------------------------------------------------
647 |   Facility      :  libnform  
648 |   Function      :  bool new_page(const FIELD *field)
649 |   
650 |   Description   :  Retrieve the info whether or not the field starts a
651 |                    new page on the form.
652 |
653 |   Return Values :  TRUE  - field starts a new page
654 |                    FALSE - field doesn't start a new page
655 +--------------------------------------------------------------------------*/
656 bool new_page(const FIELD * field)
657 {
658   return (Normalize_Field(field)->status & _NEWPAGE)  ? TRUE : FALSE;
659 }
660
661 /* fld_def.c ends here */