xref: /freebsd/contrib/ncurses/form/fty_generic.c (revision 62cfcf62f627e5093fb37026a6d8c98e4d2ef04c)
1 /****************************************************************************
2  * Copyright 2018,2020 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.10 2020/02/02 23:34:34 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. Especially 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 allowes 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  * The languages can register a new generic fieldtype dynamically and store
49  * a handle (key) to the calling object as an argument. Together with that
50  * it can register a freearg callback, so that the high level language
51  * remains in control of the memory management of the arguments they pass.
52  * The design idea is, that the high-level language - typically a OO
53  * language like C# or Java, uses it's own dispatching mechanisms
54  * (polymorphism) to call the proper check routines responsible for the
55  * argument type. So these language implement typically only one generic
56  * fieldtype they register with the forms library using this call.
57  *
58  * For that purpose we have extended the fieldtype struc by a new element
59  * that gets the arguments from a single struct passed by the caller.
60  *
61  */
62 #if NCURSES_INTEROP_FUNCS
63 
64 /*---------------------------------------------------------------------------
65 |   Facility      :  libnform
66 |   Function      :  static void *Generic_This_Type( void * arg )
67 |
68 |   Description   :  We interpret the passed arg just as a handle the
69 |                    calling language uses to keep track of its allocated
70 |                    argument structures. We can simply copy it back.
71 |
72 |   Return Values :  Pointer to argument structure
73 +--------------------------------------------------------------------------*/
74 static void *
75 Generic_This_Type(void *arg)
76 {
77   return (arg);
78 }
79 
80 /*---------------------------------------------------------------------------
81 |   Facility      :  libnform
82 |   Function      :  FIELDTYPE *_nc_generic_fieldtype(
83 |                       bool (* const field_check)(FIELD *,const void *),
84 |                       bool (* const char_check) (int, const void *),
85 |   		        bool (*const next)(FORM*,FIELD*,const void*),
86 |		        bool (*const prev)(FORM*,FIELD*,const void*),
87 |                       void (*freecallback)(void*))
88 |
89 |   Description   :  Create a new fieldtype. The application programmer must
90 |                    write a field_check and a char_check function and give
91 |                    them as input to this call. A callback to allow the
92 |                    release of the allocated memory must also be provided.
93 |                    For generic field types, we provide some more
94 |                    information about the field as parameters.
95 |
96 |                    If an error occurs, errno is set to
97 |                       E_BAD_ARGUMENT  - invalid arguments
98 |                       E_SYSTEM_ERROR  - system error (no memory)
99 |
100 |   Return Values :  Fieldtype pointer or NULL if error occurred
101 +--------------------------------------------------------------------------*/
102 NCURSES_EXPORT(FIELDTYPE *)
103 _nc_generic_fieldtype(bool (*const field_check) (FORM *, FIELD *, const void *),
104 		      bool (*const char_check) (int, FORM *, FIELD *, const
105 						void *),
106 		      bool (*const next) (FORM *, FIELD *, const void *),
107 		      bool (*const prev) (FORM *, FIELD *, const void *),
108 		      void (*freecallback) (void *))
109 {
110   int code = E_SYSTEM_ERROR;
111   FIELDTYPE *res = (FIELDTYPE *)0;
112 
113   TR_FUNC_BFR(5);
114 
115   T((T_CALLED("_nc_generic_fieldtype(%s,%s,%s,%s,%s)"),
116      TR_FUNC_ARG(0, field_check),
117      TR_FUNC_ARG(1, char_check),
118      TR_FUNC_ARG(2, next),
119      TR_FUNC_ARG(3, prev),
120      TR_FUNC_ARG(4, freecallback)));
121 
122   if (field_check || char_check)
123     {
124       res = typeMalloc(FIELDTYPE, 1);
125 
126       if (res)
127 	{
128 	  *res = *_nc_Default_FieldType;
129 	  SetStatus(res, (_HAS_ARGS | _GENERIC));
130 	  res->fieldcheck.gfcheck = field_check;
131 	  res->charcheck.gccheck = char_check;
132 	  res->genericarg = Generic_This_Type;
133 	  res->freearg = freecallback;
134 	  res->enum_next.gnext = next;
135 	  res->enum_prev.gprev = prev;
136 	  code = E_OK;
137 	}
138     }
139   else
140     code = E_BAD_ARGUMENT;
141 
142   if (E_OK != code)
143     SET_ERROR(code);
144 
145   returnFieldType(res);
146 }
147 
148 /*---------------------------------------------------------------------------
149 |   Facility      :  libnform
150 |   Function      :  static TypeArgument *GenericArgument(
151 |                      const FIELDTYPE* typ,
152 |                      int (*argiterator)(void**),
153 |                      int* err)
154 |
155 |   Description   :  The iterator callback must browse through all fieldtype
156 |                    parameters that have an argument associated with the
157 |                    type. The iterator returns 1 if the operation to get
158 |                    the next element was successful, 0 otherwise. If the
159 |                    iterator could move to the next argument, it fills
160 |                    the void* pointer representing the argument into the
161 |                    location provided as argument to the iterator.
162 |                    The err reference is used to keep track of errors.
163 |
164 |   Return Values :  Pointer to argument structure
165 +--------------------------------------------------------------------------*/
166 static TypeArgument *
167 GenericArgument(const FIELDTYPE *typ,
168 		int (*argiterator) (void **), int *err)
169 {
170   TypeArgument *res = (TypeArgument *)0;
171 
172   if (typ != 0 && (typ->status & _HAS_ARGS) != 0 && err != 0 && argiterator != 0)
173     {
174       if (typ->status & _LINKED_TYPE)
175 	{
176 	  /* Composite fieldtypes keep track internally of their own memory */
177 	  TypeArgument *p = typeMalloc(TypeArgument, 1);
178 
179 	  if (p)
180 	    {
181 	      p->left = GenericArgument(typ->left, argiterator, err);
182 	      p->right = GenericArgument(typ->right, argiterator, err);
183 	      return p;
184 	    }
185 	  else
186 	    *err += 1;
187 	}
188       else
189 	{
190 	  assert(typ->genericarg != (void *)0);
191 	  if (typ->genericarg == 0)
192 	    *err += 1;
193 	  else
194 	    {
195 	      void *argp;
196 	      int valid = argiterator(&argp);
197 
198 	      if (valid == 0 || argp == 0 ||
199 		  !(res = (TypeArgument *)typ->genericarg(argp)))
200 		{
201 		  *err += 1;
202 		}
203 	    }
204 	}
205     }
206   return res;
207 }
208 
209 /*---------------------------------------------------------------------------
210 |   Facility      :  libnform
211 |   Function      :  int _nc_set_generic_fieldtype(
212 |                      FIELD* field,
213 |                      FIELDTYPE* ftyp,
214 |                      int (*argiterator)(void**))
215 |
216 |   Description   :  Assign the fieldtype to the field and use the iterator
217 |                    mechanism to get the arguments when a check is
218 |                    performed.
219 |
220 |   Return Values :  E_OK if all went well
221 |                    E_SYSTEM_ERROR if an error occurred
222 +--------------------------------------------------------------------------*/
223 NCURSES_EXPORT(int)
224 _nc_set_generic_fieldtype(FIELD *field,
225 			  FIELDTYPE *ftyp,
226 			  int (*argiterator) (void **))
227 {
228   int code = E_SYSTEM_ERROR;
229   int err = 0;
230 
231   if (field)
232     {
233       if (field && field->type)
234 	_nc_Free_Type(field);
235 
236       field->type = ftyp;
237       if (ftyp)
238 	{
239 	  if (argiterator)
240 	    {
241 	      /* The precondition is that the iterator is reset */
242 	      field->arg = (void *)GenericArgument(field->type, argiterator, &err);
243 
244 	      if (err)
245 		{
246 		  _nc_Free_Argument(field->type, (TypeArgument *)(field->arg));
247 		  field->type = (FIELDTYPE *)0;
248 		  field->arg = (void *)0;
249 		}
250 	      else
251 		{
252 		  code = E_OK;
253 		  if (field->type)
254 		    field->type->ref++;
255 		}
256 	    }
257 	}
258       else
259 	{
260 	  field->arg = (void *)0;
261 	  code = E_OK;
262 	}
263     }
264   return code;
265 }
266 
267 /*---------------------------------------------------------------------------
268 |   Facility      :  libnform
269 |   Function      :  WINDOW* _nc_form_cursor(
270 |                      FORM* form,
271 |                      int *pRow, int *pCol)
272 |
273 |   Description   :  Get the current position of the form cursor position
274 |                    We also return the field window
275 |
276 |   Return Values :  The fields Window or NULL on error
277 +--------------------------------------------------------------------------*/
278 NCURSES_EXPORT(WINDOW *)
279 _nc_form_cursor(const FORM *form, int *pRow, int *pCol)
280 {
281   int code = E_SYSTEM_ERROR;
282   WINDOW *res = (WINDOW *)0;
283 
284   if (!(form == 0 || pRow == 0 || pCol == 0))
285     {
286       *pRow = form->currow;
287       *pCol = form->curcol;
288       res = form->w;
289       code = E_OK;
290     }
291   if (code != E_OK)
292     SET_ERROR(code);
293   return res;
294 }
295 
296 #else
297 extern void _nc_fty_generic(void);
298 void
299 _nc_fty_generic(void)
300 {
301 }
302 #endif
303 
304 /* fty_generic.c ends here */
305