xref: /openbsd-src/lib/libform/fty_generic.c (revision c7ef0cfc17afcba97172c25e1e3a943e893bc632)
1*c7ef0cfcSnicm /****************************************************************************
2*c7ef0cfcSnicm  * Copyright 2018-2020,2021 Thomas E. Dickey                                *
3*c7ef0cfcSnicm  * Copyright 2008-2012,2016 Free Software Foundation, Inc.                  *
4*c7ef0cfcSnicm  *                                                                          *
5*c7ef0cfcSnicm  * Permission is hereby granted, free of charge, to any person obtaining a  *
6*c7ef0cfcSnicm  * copy of this software and associated documentation files (the            *
7*c7ef0cfcSnicm  * "Software"), to deal in the Software without restriction, including      *
8*c7ef0cfcSnicm  * without limitation the rights to use, copy, modify, merge, publish,      *
9*c7ef0cfcSnicm  * distribute, distribute with modifications, sublicense, and/or sell       *
10*c7ef0cfcSnicm  * copies of the Software, and to permit persons to whom the Software is    *
11*c7ef0cfcSnicm  * furnished to do so, subject to the following conditions:                 *
12*c7ef0cfcSnicm  *                                                                          *
13*c7ef0cfcSnicm  * The above copyright notice and this permission notice shall be included  *
14*c7ef0cfcSnicm  * in all copies or substantial portions of the Software.                   *
15*c7ef0cfcSnicm  *                                                                          *
16*c7ef0cfcSnicm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17*c7ef0cfcSnicm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18*c7ef0cfcSnicm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19*c7ef0cfcSnicm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20*c7ef0cfcSnicm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21*c7ef0cfcSnicm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22*c7ef0cfcSnicm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23*c7ef0cfcSnicm  *                                                                          *
24*c7ef0cfcSnicm  * Except as contained in this notice, the name(s) of the above copyright   *
25*c7ef0cfcSnicm  * holders shall not be used in advertising or otherwise to promote the     *
26*c7ef0cfcSnicm  * sale, use or other dealings in this Software without prior written       *
27*c7ef0cfcSnicm  * authorization.                                                           *
28*c7ef0cfcSnicm  ****************************************************************************/
29*c7ef0cfcSnicm 
30*c7ef0cfcSnicm /***************************************************************************
31*c7ef0cfcSnicm *                                                                          *
32*c7ef0cfcSnicm *  Author : Juergen Pfeifer                                                *
33*c7ef0cfcSnicm *                                                                          *
34*c7ef0cfcSnicm ***************************************************************************/
35*c7ef0cfcSnicm 
36*c7ef0cfcSnicm #include "form.priv.h"
37*c7ef0cfcSnicm 
38*c7ef0cfcSnicm MODULE_ID("$Id: fty_generic.c,v 1.1 2023/10/17 09:52:10 nicm Exp $")
39*c7ef0cfcSnicm 
40*c7ef0cfcSnicm /*
41*c7ef0cfcSnicm  * This is not a full implementation of a field type, but adds some
42*c7ef0cfcSnicm  * support for higher level languages with some restrictions to interop
43*c7ef0cfcSnicm  * with C language. In particular, the collection of arguments for the
44*c7ef0cfcSnicm  * various fieldtypes is not based on the vararg C mechanism, but on a
45*c7ef0cfcSnicm  * iterator based callback mechanism that allows the high level language
46*c7ef0cfcSnicm  * to provide the arguments as a structure. Most languages have mechanisms
47*c7ef0cfcSnicm  * to layout structures so that they can be passed to C.
48*c7ef0cfcSnicm  *
49*c7ef0cfcSnicm  * The languages can register a new generic fieldtype dynamically and store
50*c7ef0cfcSnicm  * a handle (key) to the calling object as an argument. Together with that
51*c7ef0cfcSnicm  * it can register a freearg callback, so that the high level language
52*c7ef0cfcSnicm  * remains in control of the memory management of the arguments they pass.
53*c7ef0cfcSnicm  * The design idea is, that the high-level language - typically a OO
54*c7ef0cfcSnicm  * language like C# or Java, uses its own dispatching mechanisms
55*c7ef0cfcSnicm  * (polymorphism) to call the proper check routines responsible for the
56*c7ef0cfcSnicm  * argument type. So these language implement typically only one generic
57*c7ef0cfcSnicm  * fieldtype they register with the forms library using this call.
58*c7ef0cfcSnicm  *
59*c7ef0cfcSnicm  * For that purpose we have extended the fieldtype structure by a new element
60*c7ef0cfcSnicm  * that gets the arguments from a single struct passed by the caller.
61*c7ef0cfcSnicm  *
62*c7ef0cfcSnicm  */
63*c7ef0cfcSnicm #if NCURSES_INTEROP_FUNCS
64*c7ef0cfcSnicm 
65*c7ef0cfcSnicm /*---------------------------------------------------------------------------
66*c7ef0cfcSnicm |   Facility      :  libnform
67*c7ef0cfcSnicm |   Function      :  static void *Generic_This_Type( void * arg )
68*c7ef0cfcSnicm |
69*c7ef0cfcSnicm |   Description   :  We interpret the passed arg just as a handle the
70*c7ef0cfcSnicm |                    calling language uses to keep track of its allocated
71*c7ef0cfcSnicm |                    argument structures. We can simply copy it back.
72*c7ef0cfcSnicm |
73*c7ef0cfcSnicm |   Return Values :  Pointer to argument structure
74*c7ef0cfcSnicm +--------------------------------------------------------------------------*/
75*c7ef0cfcSnicm static void *
Generic_This_Type(void * arg)76*c7ef0cfcSnicm Generic_This_Type(void *arg)
77*c7ef0cfcSnicm {
78*c7ef0cfcSnicm   return (arg);
79*c7ef0cfcSnicm }
80*c7ef0cfcSnicm 
81*c7ef0cfcSnicm /*---------------------------------------------------------------------------
82*c7ef0cfcSnicm |   Facility      :  libnform
83*c7ef0cfcSnicm |   Function      :  FIELDTYPE *_nc_generic_fieldtype(
84*c7ef0cfcSnicm |                       bool (* const field_check)(FIELD *,const void *),
85*c7ef0cfcSnicm |                       bool (* const char_check) (int, const void *),
86*c7ef0cfcSnicm |   		        bool (*const next)(FORM*,FIELD*,const void*),
87*c7ef0cfcSnicm |		        bool (*const prev)(FORM*,FIELD*,const void*),
88*c7ef0cfcSnicm |                       void (*freecallback)(void*))
89*c7ef0cfcSnicm |
90*c7ef0cfcSnicm |   Description   :  Create a new fieldtype. The application programmer must
91*c7ef0cfcSnicm |                    write a field_check and a char_check function and give
92*c7ef0cfcSnicm |                    them as input to this call. A callback to allow the
93*c7ef0cfcSnicm |                    release of the allocated memory must also be provided.
94*c7ef0cfcSnicm |                    For generic field types, we provide some more
95*c7ef0cfcSnicm |                    information about the field as parameters.
96*c7ef0cfcSnicm |
97*c7ef0cfcSnicm |                    If an error occurs, errno is set to
98*c7ef0cfcSnicm |                       E_BAD_ARGUMENT  - invalid arguments
99*c7ef0cfcSnicm |                       E_SYSTEM_ERROR  - system error (no memory)
100*c7ef0cfcSnicm |
101*c7ef0cfcSnicm |   Return Values :  Fieldtype pointer or NULL if error occurred
102*c7ef0cfcSnicm +--------------------------------------------------------------------------*/
103*c7ef0cfcSnicm FORM_EXPORT(FIELDTYPE *)
_nc_generic_fieldtype(bool (* const field_check)(FORM *,FIELD *,const void *),bool (* const char_check)(int,FORM *,FIELD *,const void *),bool (* const next)(FORM *,FIELD *,const void *),bool (* const prev)(FORM *,FIELD *,const void *),void (* freecallback)(void *))104*c7ef0cfcSnicm _nc_generic_fieldtype(bool (*const field_check) (FORM *, FIELD *, const void *),
105*c7ef0cfcSnicm 		      bool (*const char_check) (int, FORM *, FIELD *, const
106*c7ef0cfcSnicm 						void *),
107*c7ef0cfcSnicm 		      bool (*const next) (FORM *, FIELD *, const void *),
108*c7ef0cfcSnicm 		      bool (*const prev) (FORM *, FIELD *, const void *),
109*c7ef0cfcSnicm 		      void (*freecallback) (void *))
110*c7ef0cfcSnicm {
111*c7ef0cfcSnicm   int code = E_SYSTEM_ERROR;
112*c7ef0cfcSnicm   FIELDTYPE *res = (FIELDTYPE *)0;
113*c7ef0cfcSnicm 
114*c7ef0cfcSnicm   TR_FUNC_BFR(5);
115*c7ef0cfcSnicm 
116*c7ef0cfcSnicm   T((T_CALLED("_nc_generic_fieldtype(%s,%s,%s,%s,%s)"),
117*c7ef0cfcSnicm      TR_FUNC_ARG(0, field_check),
118*c7ef0cfcSnicm      TR_FUNC_ARG(1, char_check),
119*c7ef0cfcSnicm      TR_FUNC_ARG(2, next),
120*c7ef0cfcSnicm      TR_FUNC_ARG(3, prev),
121*c7ef0cfcSnicm      TR_FUNC_ARG(4, freecallback)));
122*c7ef0cfcSnicm 
123*c7ef0cfcSnicm   if (field_check || char_check)
124*c7ef0cfcSnicm     {
125*c7ef0cfcSnicm       res = typeMalloc(FIELDTYPE, 1);
126*c7ef0cfcSnicm 
127*c7ef0cfcSnicm       if (res)
128*c7ef0cfcSnicm 	{
129*c7ef0cfcSnicm 	  *res = *_nc_Default_FieldType;
130*c7ef0cfcSnicm 	  SetStatus(res, (_HAS_ARGS | _GENERIC));
131*c7ef0cfcSnicm 	  res->fieldcheck.gfcheck = field_check;
132*c7ef0cfcSnicm 	  res->charcheck.gccheck = char_check;
133*c7ef0cfcSnicm 	  res->genericarg = Generic_This_Type;
134*c7ef0cfcSnicm 	  res->freearg = freecallback;
135*c7ef0cfcSnicm 	  res->enum_next.gnext = next;
136*c7ef0cfcSnicm 	  res->enum_prev.gprev = prev;
137*c7ef0cfcSnicm 	  code = E_OK;
138*c7ef0cfcSnicm 	}
139*c7ef0cfcSnicm     }
140*c7ef0cfcSnicm   else
141*c7ef0cfcSnicm     code = E_BAD_ARGUMENT;
142*c7ef0cfcSnicm 
143*c7ef0cfcSnicm   if (E_OK != code)
144*c7ef0cfcSnicm     SET_ERROR(code);
145*c7ef0cfcSnicm 
146*c7ef0cfcSnicm   returnFieldType(res);
147*c7ef0cfcSnicm }
148*c7ef0cfcSnicm 
149*c7ef0cfcSnicm /*---------------------------------------------------------------------------
150*c7ef0cfcSnicm |   Facility      :  libnform
151*c7ef0cfcSnicm |   Function      :  static TypeArgument *GenericArgument(
152*c7ef0cfcSnicm |                      const FIELDTYPE* typ,
153*c7ef0cfcSnicm |                      int (*argiterator)(void**),
154*c7ef0cfcSnicm |                      int* err)
155*c7ef0cfcSnicm |
156*c7ef0cfcSnicm |   Description   :  The iterator callback must browse through all fieldtype
157*c7ef0cfcSnicm |                    parameters that have an argument associated with the
158*c7ef0cfcSnicm |                    type. The iterator returns 1 if the operation to get
159*c7ef0cfcSnicm |                    the next element was successful, 0 otherwise. If the
160*c7ef0cfcSnicm |                    iterator could move to the next argument, it fills
161*c7ef0cfcSnicm |                    the void* pointer representing the argument into the
162*c7ef0cfcSnicm |                    location provided as argument to the iterator.
163*c7ef0cfcSnicm |                    The err reference is used to keep track of errors.
164*c7ef0cfcSnicm |
165*c7ef0cfcSnicm |   Return Values :  Pointer to argument structure
166*c7ef0cfcSnicm +--------------------------------------------------------------------------*/
167*c7ef0cfcSnicm static TypeArgument *
GenericArgument(const FIELDTYPE * typ,int (* argiterator)(void **),int * err)168*c7ef0cfcSnicm GenericArgument(const FIELDTYPE *typ,
169*c7ef0cfcSnicm 		int (*argiterator) (void **), int *err)
170*c7ef0cfcSnicm {
171*c7ef0cfcSnicm   TypeArgument *res = (TypeArgument *)0;
172*c7ef0cfcSnicm 
173*c7ef0cfcSnicm   if (typ != 0 && (typ->status & _HAS_ARGS) != 0 && err != 0 && argiterator != 0)
174*c7ef0cfcSnicm     {
175*c7ef0cfcSnicm       if (typ->status & _LINKED_TYPE)
176*c7ef0cfcSnicm 	{
177*c7ef0cfcSnicm 	  /* Composite fieldtypes keep track internally of their own memory */
178*c7ef0cfcSnicm 	  TypeArgument *p = typeMalloc(TypeArgument, 1);
179*c7ef0cfcSnicm 
180*c7ef0cfcSnicm 	  if (p)
181*c7ef0cfcSnicm 	    {
182*c7ef0cfcSnicm 	      p->left = GenericArgument(typ->left, argiterator, err);
183*c7ef0cfcSnicm 	      p->right = GenericArgument(typ->right, argiterator, err);
184*c7ef0cfcSnicm 	      return p;
185*c7ef0cfcSnicm 	    }
186*c7ef0cfcSnicm 	  else
187*c7ef0cfcSnicm 	    *err += 1;
188*c7ef0cfcSnicm 	}
189*c7ef0cfcSnicm       else
190*c7ef0cfcSnicm 	{
191*c7ef0cfcSnicm 	  assert(typ->genericarg != (void *)0);
192*c7ef0cfcSnicm 	  if (typ->genericarg == 0)
193*c7ef0cfcSnicm 	    *err += 1;
194*c7ef0cfcSnicm 	  else
195*c7ef0cfcSnicm 	    {
196*c7ef0cfcSnicm 	      void *argp;
197*c7ef0cfcSnicm 	      int valid = argiterator(&argp);
198*c7ef0cfcSnicm 
199*c7ef0cfcSnicm 	      if (valid == 0 || argp == 0 ||
200*c7ef0cfcSnicm 		  !(res = (TypeArgument *)typ->genericarg(argp)))
201*c7ef0cfcSnicm 		{
202*c7ef0cfcSnicm 		  *err += 1;
203*c7ef0cfcSnicm 		}
204*c7ef0cfcSnicm 	    }
205*c7ef0cfcSnicm 	}
206*c7ef0cfcSnicm     }
207*c7ef0cfcSnicm   return res;
208*c7ef0cfcSnicm }
209*c7ef0cfcSnicm 
210*c7ef0cfcSnicm /*---------------------------------------------------------------------------
211*c7ef0cfcSnicm |   Facility      :  libnform
212*c7ef0cfcSnicm |   Function      :  int _nc_set_generic_fieldtype(
213*c7ef0cfcSnicm |                      FIELD* field,
214*c7ef0cfcSnicm |                      FIELDTYPE* ftyp,
215*c7ef0cfcSnicm |                      int (*argiterator)(void**))
216*c7ef0cfcSnicm |
217*c7ef0cfcSnicm |   Description   :  Assign the fieldtype to the field and use the iterator
218*c7ef0cfcSnicm |                    mechanism to get the arguments when a check is
219*c7ef0cfcSnicm |                    performed.
220*c7ef0cfcSnicm |
221*c7ef0cfcSnicm |   Return Values :  E_OK if all went well
222*c7ef0cfcSnicm |                    E_SYSTEM_ERROR if an error occurred
223*c7ef0cfcSnicm +--------------------------------------------------------------------------*/
224*c7ef0cfcSnicm FORM_EXPORT(int)
_nc_set_generic_fieldtype(FIELD * field,FIELDTYPE * ftyp,int (* argiterator)(void **))225*c7ef0cfcSnicm _nc_set_generic_fieldtype(FIELD *field,
226*c7ef0cfcSnicm 			  FIELDTYPE *ftyp,
227*c7ef0cfcSnicm 			  int (*argiterator) (void **))
228*c7ef0cfcSnicm {
229*c7ef0cfcSnicm   int code = E_SYSTEM_ERROR;
230*c7ef0cfcSnicm   int err = 0;
231*c7ef0cfcSnicm 
232*c7ef0cfcSnicm   if (field)
233*c7ef0cfcSnicm     {
234*c7ef0cfcSnicm       if (field && field->type)
235*c7ef0cfcSnicm 	_nc_Free_Type(field);
236*c7ef0cfcSnicm 
237*c7ef0cfcSnicm       field->type = ftyp;
238*c7ef0cfcSnicm       if (ftyp)
239*c7ef0cfcSnicm 	{
240*c7ef0cfcSnicm 	  if (argiterator)
241*c7ef0cfcSnicm 	    {
242*c7ef0cfcSnicm 	      /* The precondition is that the iterator is reset */
243*c7ef0cfcSnicm 	      field->arg = (void *)GenericArgument(field->type, argiterator, &err);
244*c7ef0cfcSnicm 
245*c7ef0cfcSnicm 	      if (err)
246*c7ef0cfcSnicm 		{
247*c7ef0cfcSnicm 		  _nc_Free_Argument(field->type, (TypeArgument *)(field->arg));
248*c7ef0cfcSnicm 		  field->type = (FIELDTYPE *)0;
249*c7ef0cfcSnicm 		  field->arg = (void *)0;
250*c7ef0cfcSnicm 		}
251*c7ef0cfcSnicm 	      else
252*c7ef0cfcSnicm 		{
253*c7ef0cfcSnicm 		  code = E_OK;
254*c7ef0cfcSnicm 		  if (field->type)
255*c7ef0cfcSnicm 		    field->type->ref++;
256*c7ef0cfcSnicm 		}
257*c7ef0cfcSnicm 	    }
258*c7ef0cfcSnicm 	}
259*c7ef0cfcSnicm       else
260*c7ef0cfcSnicm 	{
261*c7ef0cfcSnicm 	  field->arg = (void *)0;
262*c7ef0cfcSnicm 	  code = E_OK;
263*c7ef0cfcSnicm 	}
264*c7ef0cfcSnicm     }
265*c7ef0cfcSnicm   return code;
266*c7ef0cfcSnicm }
267*c7ef0cfcSnicm 
268*c7ef0cfcSnicm /*---------------------------------------------------------------------------
269*c7ef0cfcSnicm |   Facility      :  libnform
270*c7ef0cfcSnicm |   Function      :  WINDOW* _nc_form_cursor(
271*c7ef0cfcSnicm |                      FORM* form,
272*c7ef0cfcSnicm |                      int *pRow, int *pCol)
273*c7ef0cfcSnicm |
274*c7ef0cfcSnicm |   Description   :  Get the current position of the form cursor position
275*c7ef0cfcSnicm |                    We also return the field window
276*c7ef0cfcSnicm |
277*c7ef0cfcSnicm |   Return Values :  The field's Window or NULL on error
278*c7ef0cfcSnicm +--------------------------------------------------------------------------*/
279*c7ef0cfcSnicm FORM_EXPORT(WINDOW *)
_nc_form_cursor(const FORM * form,int * pRow,int * pCol)280*c7ef0cfcSnicm _nc_form_cursor(const FORM *form, int *pRow, int *pCol)
281*c7ef0cfcSnicm {
282*c7ef0cfcSnicm   int code = E_SYSTEM_ERROR;
283*c7ef0cfcSnicm   WINDOW *res = (WINDOW *)0;
284*c7ef0cfcSnicm 
285*c7ef0cfcSnicm   if (form != 0 && pRow != 0 && pCol != 0)
286*c7ef0cfcSnicm     {
287*c7ef0cfcSnicm       *pRow = form->currow;
288*c7ef0cfcSnicm       *pCol = form->curcol;
289*c7ef0cfcSnicm       res = form->w;
290*c7ef0cfcSnicm       code = E_OK;
291*c7ef0cfcSnicm     }
292*c7ef0cfcSnicm   if (code != E_OK)
293*c7ef0cfcSnicm     SET_ERROR(code);
294*c7ef0cfcSnicm   return res;
295*c7ef0cfcSnicm }
296*c7ef0cfcSnicm 
297*c7ef0cfcSnicm #else
298*c7ef0cfcSnicm extern void _nc_fty_generic(void);
299*c7ef0cfcSnicm void
300*c7ef0cfcSnicm _nc_fty_generic(void)
301*c7ef0cfcSnicm {
302*c7ef0cfcSnicm }
303*c7ef0cfcSnicm #endif
304*c7ef0cfcSnicm 
305*c7ef0cfcSnicm /* fty_generic.c ends here */
306