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