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