xref: /openbsd-src/lib/libform/frm_def.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: frm_def.c,v 1.6 2001/01/22 18:02:14 millert Exp $	*/
2 
3 /****************************************************************************
4  * Copyright (c) 1998,2000 Free Software Foundation, Inc.                   *
5  *                                                                          *
6  * Permission is hereby granted, free of charge, to any person obtaining a  *
7  * copy of this software and associated documentation files (the            *
8  * "Software"), to deal in the Software without restriction, including      *
9  * without limitation the rights to use, copy, modify, merge, publish,      *
10  * distribute, distribute with modifications, sublicense, and/or sell       *
11  * copies of the Software, and to permit persons to whom the Software is    *
12  * furnished to do so, subject to the following conditions:                 *
13  *                                                                          *
14  * The above copyright notice and this permission notice shall be included  *
15  * in all copies or substantial portions of the Software.                   *
16  *                                                                          *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24  *                                                                          *
25  * Except as contained in this notice, the name(s) of the above copyright   *
26  * holders shall not be used in advertising or otherwise to promote the     *
27  * sale, use or other dealings in this Software without prior written       *
28  * authorization.                                                           *
29  ****************************************************************************/
30 
31 /****************************************************************************
32  *   Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997            *
33  ****************************************************************************/
34 
35 #include "form.priv.h"
36 
37 MODULE_ID("$From: frm_def.c,v 1.10 2000/12/10 02:09:38 tom Exp $")
38 
39 /* this can't be readonly */
40 static FORM default_form = {
41   0,                                    /* status     */
42   0,                                    /* rows       */
43   0,                                    /* cols       */
44   0,                                    /* currow     */
45   0,                                    /* curcol     */
46   0,                                    /* toprow     */
47   0,                                    /* begincol   */
48   -1,                                   /* maxfield   */
49   -1,                                   /* maxpage    */
50   -1,                                   /* curpage    */
51   ALL_FORM_OPTS,                        /* opts       */
52   (WINDOW *)0,                          /* win        */
53   (WINDOW *)0,                          /* sub        */
54   (WINDOW *)0,                          /* w          */
55   (FIELD **)0,                          /* field      */
56   (FIELD *)0,                           /* current    */
57   (_PAGE *)0,                           /* page       */
58   (char *)0,                            /* usrptr     */
59   NULL,			                /* forminit   */
60   NULL,                                 /* formterm   */
61   NULL,                                 /* fieldinit  */
62   NULL                                  /* fieldterm  */
63 };
64 
65 NCURSES_EXPORT_VAR(FORM *) _nc_Default_Form = &default_form;
66 
67 /*---------------------------------------------------------------------------
68 |   Facility      :  libnform
69 |   Function      :  static FIELD *Insert_Field_By_Position(
70 |                                     FIELD *new_field,
71 |                                     FIELD *head )
72 |
73 |   Description   :  Insert new_field into sorted fieldlist with head "head"
74 |                    and return new head of sorted fieldlist. Sorting
75 |                    criteria is (row,column). This is a circular list.
76 |
77 |   Return Values :  New head of sorted fieldlist
78 +--------------------------------------------------------------------------*/
79 static FIELD *Insert_Field_By_Position(FIELD *newfield, FIELD *head)
80 {
81   FIELD *current, *newhead;
82 
83   assert(newfield);
84 
85   if (!head)
86     { /* empty list is trivial */
87       newhead = newfield->snext = newfield->sprev = newfield;
88     }
89   else
90     {
91       newhead = current = head;
92       while((current->frow < newfield->frow) ||
93 	    ((current->frow==newfield->frow) &&
94 	     (current->fcol < newfield->fcol)) )
95 	{
96 	  current = current->snext;
97 	  if (current==head)
98 	    { /* We cycled through. Reset head to indicate that */
99 	      head = (FIELD *)0;
100 	      break;
101 	    }
102 	}
103       /* we leave the loop with current pointing to the field after newfield*/
104       newfield->snext	 = current;
105       newfield->sprev	 = current->sprev;
106       newfield->snext->sprev = newfield;
107       newfield->sprev->snext = newfield;
108       if (current==head)
109 	newhead = newfield;
110     }
111   return(newhead);
112 }
113 
114 /*---------------------------------------------------------------------------
115 |   Facility      :  libnform
116 |   Function      :  static void Disconnect_Fields(FORM *form)
117 |
118 |   Description   :  Break association between form and array of fields.
119 |
120 |   Return Values :  -
121 +--------------------------------------------------------------------------*/
122 static void Disconnect_Fields( FORM * form )
123 {
124   if (form->field)
125     {
126       FIELD **fields;
127 
128       for(fields=form->field;*fields;fields++)
129 	{
130 	  if (form == (*fields)->form)
131 	    (*fields)->form = (FORM *)0;
132 	}
133 
134       form->rows = form->cols = 0;
135       form->maxfield = form->maxpage = -1;
136       form->field = (FIELD **)0;
137       if (form->page)
138 	free(form->page);
139       form->page = (_PAGE *)0;
140     }
141 }
142 
143 /*---------------------------------------------------------------------------
144 |   Facility      :  libnform
145 |   Function      :  static int Connect_Fields(FORM *form, FIELD **fields)
146 |
147 |   Description   :  Set association between form and array of fields.
148 |
149 |   Return Values :  E_OK            - no error
150 |                    E_CONNECTED     - a field is already connected
151 |                    E_BAD_ARGUMENT  - Invalid form pointer or field array
152 |                    E_SYSTEM_ERROR  - not enough memory
153 +--------------------------------------------------------------------------*/
154 static int Connect_Fields(FORM  * form, FIELD ** fields)
155 {
156   int field_cnt, j;
157   int page_nr;
158   int maximum_row_in_field, maximum_col_in_field;
159   _PAGE *pg;
160 
161   assert(form);
162 
163   form->field    = fields;
164   form->maxfield = 0;
165   form->maxpage  = 0;
166 
167   if (!fields)
168     RETURN(E_OK);
169 
170   page_nr = 0;
171   /* store formpointer in fields and count pages */
172   for(field_cnt=0;fields[field_cnt];field_cnt++)
173     {
174       if (fields[field_cnt]->form)
175 	RETURN(E_CONNECTED);
176       if ( field_cnt==0 ||
177 	  (fields[field_cnt]->status & _NEWPAGE))
178 	page_nr++;
179       fields[field_cnt]->form = form;
180     }
181   if (field_cnt==0)
182     RETURN(E_BAD_ARGUMENT);
183 
184   /* allocate page structures */
185   if ( (pg = (_PAGE *)malloc(page_nr * sizeof(_PAGE))) != (_PAGE *)0 )
186     {
187       form->page = pg;
188     }
189   else
190     RETURN(E_SYSTEM_ERROR);
191 
192   /* Cycle through fields and calculate page boundaries as well as
193      size of the form */
194   for(j=0;j<field_cnt;j++)
195     {
196       if (j==0)
197 	pg->pmin = j;
198       else
199 	{
200 	  if (fields[j]->status & _NEWPAGE)
201 	    {
202 	      pg->pmax = j-1;
203 	      pg++;
204 	      pg->pmin = j;
205 	    }
206 	}
207 
208       maximum_row_in_field = fields[j]->frow + fields[j]->rows;
209       maximum_col_in_field = fields[j]->fcol + fields[j]->cols;
210 
211       if (form->rows < maximum_row_in_field)
212 	form->rows = maximum_row_in_field;
213       if (form->cols < maximum_col_in_field)
214 	form->cols = maximum_col_in_field;
215     }
216 
217   pg->pmax       = field_cnt-1;
218   form->maxfield = field_cnt;
219   form->maxpage  = page_nr;
220 
221   /* Sort fields on form pages */
222   for(page_nr = 0;page_nr < form->maxpage; page_nr++)
223     {
224       FIELD *fld = (FIELD *)0;
225       for(j = form->page[page_nr].pmin;j <= form->page[page_nr].pmax;j++)
226 	{
227 	  fields[j]->index = j;
228 	  fields[j]->page  = page_nr;
229 	  fld = Insert_Field_By_Position(fields[j],fld);
230 	}
231       form->page[page_nr].smin = fld->index;
232       form->page[page_nr].smax = fld->sprev->index;
233     }
234   RETURN(E_OK);
235 }
236 
237 /*---------------------------------------------------------------------------
238 |   Facility      :  libnform
239 |   Function      :  static int Associate_Fields(FORM *form, FIELD **fields)
240 |
241 |   Description   :  Set association between form and array of fields.
242 |                    If there are fields, position to first active field.
243 |
244 |   Return Values :  E_OK            - success
245 |                    any other       - error occured
246 +--------------------------------------------------------------------------*/
247 INLINE static int Associate_Fields(FORM  *form, FIELD **fields)
248 {
249   int res = Connect_Fields(form,fields);
250   if (res == E_OK)
251     {
252       if (form->maxpage>0)
253 	{
254 	  form->curpage = 0;
255 	  form_driver(form,FIRST_ACTIVE_MAGIC);
256 	}
257       else
258 	{
259 	  form->curpage = -1;
260 	  form->current = (FIELD *)0;
261 	}
262     }
263   return(res);
264 }
265 
266 /*---------------------------------------------------------------------------
267 |   Facility      :  libnform
268 |   Function      :  FORM *new_form( FIELD **fields )
269 |
270 |   Description   :  Create new form with given array of fields.
271 |
272 |   Return Values :  Pointer to form. NULL if error occured.
273 +--------------------------------------------------------------------------*/
274 NCURSES_EXPORT(FORM *)
275 new_form (FIELD ** fields)
276 {
277   int err = E_SYSTEM_ERROR;
278 
279   FORM *form = (FORM *)malloc(sizeof(FORM));
280 
281   if (form)
282     {
283       *form = *_nc_Default_Form;
284       if ((err=Associate_Fields(form,fields))!=E_OK)
285 	{
286 	  free_form(form);
287 	  form = (FORM *)0;
288 	}
289     }
290 
291   if (!form)
292     SET_ERROR(err);
293 
294   return(form);
295 }
296 
297 /*---------------------------------------------------------------------------
298 |   Facility      :  libnform
299 |   Function      :  int free_form( FORM *form )
300 |
301 |   Description   :  Release internal memory associated with form.
302 |
303 |   Return Values :  E_OK           - no error
304 |                    E_BAD_ARGUMENT - invalid form pointer
305 |                    E_POSTED       - form is posted
306 +--------------------------------------------------------------------------*/
307 NCURSES_EXPORT(int)
308 free_form (FORM * form)
309 {
310   if ( !form )
311     RETURN(E_BAD_ARGUMENT);
312 
313   if ( form->status & _POSTED)
314     RETURN(E_POSTED);
315 
316   Disconnect_Fields( form );
317   if (form->page)
318     free(form->page);
319   free(form);
320 
321   RETURN(E_OK);
322 }
323 
324 /*---------------------------------------------------------------------------
325 |   Facility      :  libnform
326 |   Function      :  int set_form_fields( FORM *form, FIELD **fields )
327 |
328 |   Description   :  Set a new association of an array of fields to a form
329 |
330 |   Return Values :  E_OK              - no error
331 |                    E_BAD_ARGUMENT    - invalid form pointer
332 |                    E_POSTED          - form is posted
333 +--------------------------------------------------------------------------*/
334 NCURSES_EXPORT(int)
335 set_form_fields (FORM  * form, FIELD ** fields)
336 {
337   FIELD **old;
338   int res;
339 
340   if ( !form )
341     RETURN(E_BAD_ARGUMENT);
342 
343   if ( form->status & _POSTED )
344     RETURN(E_POSTED);
345 
346   old = form->field;
347   Disconnect_Fields( form );
348 
349   if( (res = Associate_Fields( form, fields )) != E_OK )
350     Connect_Fields( form, old );
351 
352   RETURN(res);
353 }
354 
355 /*---------------------------------------------------------------------------
356 |   Facility      :  libnform
357 |   Function      :  FIELD **form_fields( const FORM *form )
358 |
359 |   Description   :  Retrieve array of fields
360 |
361 |   Return Values :  Pointer to field array
362 +--------------------------------------------------------------------------*/
363 NCURSES_EXPORT(FIELD **)
364 form_fields (const FORM * form)
365 {
366   return (Normalize_Form( form )->field);
367 }
368 
369 /*---------------------------------------------------------------------------
370 |   Facility      :  libnform
371 |   Function      :  int field_count( const FORM *form )
372 |
373 |   Description   :  Retrieve number of fields
374 |
375 |   Return Values :  Number of fields, -1 if none are defined
376 +--------------------------------------------------------------------------*/
377 NCURSES_EXPORT(int)
378 field_count (const FORM * form)
379 {
380   return (Normalize_Form( form )->maxfield);
381 }
382 
383 /* frm_def.c ends here */
384