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