blob: 301c80a1f07aa6befea5810b96554bfaba915817 [file] [log] [blame]
Steve Kondikae271bc2015-11-15 02:50:53 +01001/****************************************************************************
micky3879b9f5e72025-07-08 18:04:53 -04002 * Copyright 2018-2020,2021 Thomas E. Dickey *
3 * Copyright 2008-2012,2016 Free Software Foundation, Inc. *
Steve Kondikae271bc2015-11-15 02:50:53 +01004 * *
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
micky3879b9f5e72025-07-08 18:04:53 -040038MODULE_ID("$Id: fty_generic.c,v 1.15 2021/03/27 23:49:53 tom Exp $")
Steve Kondikae271bc2015-11-15 02:50:53 +010039
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
micky3879b9f5e72025-07-08 18:04:53 -040043 * with C language. In particular, the collection of arguments for the
Steve Kondikae271bc2015-11-15 02:50:53 +010044 * various fieldtypes is not based on the vararg C mechanism, but on a
micky3879b9f5e72025-07-08 18:04:53 -040045 * iterator based callback mechanism that allows the high level language
Steve Kondikae271bc2015-11-15 02:50:53 +010046 * to provide the arguments as a structure. Most languages have mechanisms
47 * to layout structures so that they can be passed to C.
micky3879b9f5e72025-07-08 18:04:53 -040048 *
Steve Kondikae271bc2015-11-15 02:50:53 +010049 * 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
micky3879b9f5e72025-07-08 18:04:53 -040054 * language like C# or Java, uses its own dispatching mechanisms
Steve Kondikae271bc2015-11-15 02:50:53 +010055 * (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 *
micky3879b9f5e72025-07-08 18:04:53 -040059 * 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 *
Steve Kondikae271bc2015-11-15 02:50:53 +010062 */
63#if NCURSES_INTEROP_FUNCS
64
65/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -040066| Facility : libnform
Steve Kondikae271bc2015-11-15 02:50:53 +010067| Function : static void *Generic_This_Type( void * arg )
micky3879b9f5e72025-07-08 18:04:53 -040068|
Steve Kondikae271bc2015-11-15 02:50:53 +010069| 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+--------------------------------------------------------------------------*/
75static void *
76Generic_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.
micky3879b9f5e72025-07-08 18:04:53 -040094| For generic field types, we provide some more
Steve Kondikae271bc2015-11-15 02:50:53 +010095| 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+--------------------------------------------------------------------------*/
micky3879b9f5e72025-07-08 18:04:53 -0400103FORM_EXPORT(FIELDTYPE *)
Steve Kondikae271bc2015-11-15 02:50:53 +0100104_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
micky3879b9f5e72025-07-08 18:04:53 -0400114 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)));
Steve Kondikae271bc2015-11-15 02:50:53 +0100122
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/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400150| Facility : libnform
Steve Kondikae271bc2015-11-15 02:50:53 +0100151| Function : static TypeArgument *GenericArgument(
152| const FIELDTYPE* typ,
153| int (*argiterator)(void**),
154| int* err)
micky3879b9f5e72025-07-08 18:04:53 -0400155|
Steve Kondikae271bc2015-11-15 02:50:53 +0100156| 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
micky3879b9f5e72025-07-08 18:04:53 -0400159| the next element was successful, 0 otherwise. If the
Steve Kondikae271bc2015-11-15 02:50:53 +0100160| 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+--------------------------------------------------------------------------*/
167static TypeArgument *
168GenericArgument(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/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400211| Facility : libnform
Steve Kondikae271bc2015-11-15 02:50:53 +0100212| Function : int _nc_set_generic_fieldtype(
213| FIELD* field,
214| FIELDTYPE* ftyp,
215| int (*argiterator)(void**))
micky3879b9f5e72025-07-08 18:04:53 -0400216|
Steve Kondikae271bc2015-11-15 02:50:53 +0100217| Description : Assign the fieldtype to the field and use the iterator
micky3879b9f5e72025-07-08 18:04:53 -0400218| mechanism to get the arguments when a check is
Steve Kondikae271bc2015-11-15 02:50:53 +0100219| performed.
220|
221| Return Values : E_OK if all went well
222| E_SYSTEM_ERROR if an error occurred
223+--------------------------------------------------------------------------*/
micky3879b9f5e72025-07-08 18:04:53 -0400224FORM_EXPORT(int)
Steve Kondikae271bc2015-11-15 02:50:53 +0100225_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/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400269| Facility : libnform
Steve Kondikae271bc2015-11-15 02:50:53 +0100270| Function : WINDOW* _nc_form_cursor(
271| FORM* form,
272| int *pRow, int *pCol)
micky3879b9f5e72025-07-08 18:04:53 -0400273|
Steve Kondikae271bc2015-11-15 02:50:53 +0100274| Description : Get the current position of the form cursor position
275| We also return the field window
276|
micky3879b9f5e72025-07-08 18:04:53 -0400277| Return Values : The field's Window or NULL on error
Steve Kondikae271bc2015-11-15 02:50:53 +0100278+--------------------------------------------------------------------------*/
micky3879b9f5e72025-07-08 18:04:53 -0400279FORM_EXPORT(WINDOW *)
Steve Kondikae271bc2015-11-15 02:50:53 +0100280_nc_form_cursor(const FORM *form, int *pRow, int *pCol)
281{
282 int code = E_SYSTEM_ERROR;
283 WINDOW *res = (WINDOW *)0;
284
micky3879b9f5e72025-07-08 18:04:53 -0400285 if (form != 0 && pRow != 0 && pCol != 0)
Steve Kondikae271bc2015-11-15 02:50:53 +0100286 {
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
298extern void _nc_fty_generic(void);
299void
300_nc_fty_generic(void)
301{
302}
303#endif
304
305/* fty_generic.c ends here */