xref: /freebsd/contrib/ncurses/form/fty_generic.c (revision e18651243efbc1fe285af34e4937fd697612f1c7)
106bfebdeSXin LI /****************************************************************************
2*e1865124SBaptiste Daroussin  * Copyright 2018,2020 Thomas E. Dickey                                     *
3*e1865124SBaptiste Daroussin  * Copyright 2008-2012,2016 Free Software Foundation, Inc.                  *
406bfebdeSXin LI  *                                                                          *
506bfebdeSXin LI  * Permission is hereby granted, free of charge, to any person obtaining a  *
606bfebdeSXin LI  * copy of this software and associated documentation files (the            *
706bfebdeSXin LI  * "Software"), to deal in the Software without restriction, including      *
806bfebdeSXin LI  * without limitation the rights to use, copy, modify, merge, publish,      *
906bfebdeSXin LI  * distribute, distribute with modifications, sublicense, and/or sell       *
1006bfebdeSXin LI  * copies of the Software, and to permit persons to whom the Software is    *
1106bfebdeSXin LI  * furnished to do so, subject to the following conditions:                 *
1206bfebdeSXin LI  *                                                                          *
1306bfebdeSXin LI  * The above copyright notice and this permission notice shall be included  *
1406bfebdeSXin LI  * in all copies or substantial portions of the Software.                   *
1506bfebdeSXin LI  *                                                                          *
1606bfebdeSXin LI  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1706bfebdeSXin LI  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1806bfebdeSXin LI  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1906bfebdeSXin LI  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
2006bfebdeSXin LI  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2106bfebdeSXin LI  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2206bfebdeSXin LI  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2306bfebdeSXin LI  *                                                                          *
2406bfebdeSXin LI  * Except as contained in this notice, the name(s) of the above copyright   *
2506bfebdeSXin LI  * holders shall not be used in advertising or otherwise to promote the     *
2606bfebdeSXin LI  * sale, use or other dealings in this Software without prior written       *
2706bfebdeSXin LI  * authorization.                                                           *
2806bfebdeSXin LI  ****************************************************************************/
2906bfebdeSXin LI 
3006bfebdeSXin LI /***************************************************************************
3106bfebdeSXin LI *                                                                          *
3206bfebdeSXin LI *  Author : Juergen Pfeifer                                                *
3306bfebdeSXin LI *                                                                          *
3406bfebdeSXin LI ***************************************************************************/
3506bfebdeSXin LI 
3606bfebdeSXin LI #include "form.priv.h"
3706bfebdeSXin LI 
38*e1865124SBaptiste Daroussin MODULE_ID("$Id: fty_generic.c,v 1.10 2020/02/02 23:34:34 tom Exp $")
3906bfebdeSXin LI 
4006bfebdeSXin LI /*
4106bfebdeSXin LI  * This is not a full implementation of a field type, but adds some
4206bfebdeSXin LI  * support for higher level languages with some restrictions to interop
4306bfebdeSXin LI  * with C language. Especially the collection of arguments for the
4406bfebdeSXin LI  * various fieldtypes is not based on the vararg C mechanism, but on a
4506bfebdeSXin LI  * iterator based callback mechanism that allowes the high level language
4606bfebdeSXin LI  * to provide the arguments as a structure. Most languages have mechanisms
4706bfebdeSXin LI  * to layout structures so that they can be passed to C.
4806bfebdeSXin LI  * The languages can register a new generic fieldtype dynamically and store
4906bfebdeSXin LI  * a handle (key) to the calling object as an argument. Together with that
5006bfebdeSXin LI  * it can register a freearg callback, so that the high level language
5106bfebdeSXin LI  * remains in control of the memory management of the arguments they pass.
5206bfebdeSXin LI  * The design idea is, that the high-level language - typically a OO
5306bfebdeSXin LI  * language like C# or Java, uses it's own dispatching mechanisms
5406bfebdeSXin LI  * (polymorphism) to call the proper check routines responsible for the
5506bfebdeSXin LI  * argument type. So these language implement typically only one generic
5606bfebdeSXin LI  * fieldtype they register with the forms library using this call.
5706bfebdeSXin LI  *
5806bfebdeSXin LI  * For that purpose we have extended the fieldtype struc by a new element
5906bfebdeSXin LI  * that gets the arguments from a single struct passed by the caller.
6006bfebdeSXin LI  *
6106bfebdeSXin LI  */
6206bfebdeSXin LI #if NCURSES_INTEROP_FUNCS
6306bfebdeSXin LI 
6406bfebdeSXin LI /*---------------------------------------------------------------------------
6506bfebdeSXin LI |   Facility      :  libnform
6606bfebdeSXin LI |   Function      :  static void *Generic_This_Type( void * arg )
6706bfebdeSXin LI |
6806bfebdeSXin LI |   Description   :  We interpret the passed arg just as a handle the
6906bfebdeSXin LI |                    calling language uses to keep track of its allocated
7006bfebdeSXin LI |                    argument structures. We can simply copy it back.
7106bfebdeSXin LI |
7206bfebdeSXin LI |   Return Values :  Pointer to argument structure
7306bfebdeSXin LI +--------------------------------------------------------------------------*/
7406bfebdeSXin LI static void *
7506bfebdeSXin LI Generic_This_Type(void *arg)
7606bfebdeSXin LI {
7706bfebdeSXin LI   return (arg);
7806bfebdeSXin LI }
7906bfebdeSXin LI 
8006bfebdeSXin LI /*---------------------------------------------------------------------------
8106bfebdeSXin LI |   Facility      :  libnform
8206bfebdeSXin LI |   Function      :  FIELDTYPE *_nc_generic_fieldtype(
8306bfebdeSXin LI |                       bool (* const field_check)(FIELD *,const void *),
8406bfebdeSXin LI |                       bool (* const char_check) (int, const void *),
8506bfebdeSXin LI |   		        bool (*const next)(FORM*,FIELD*,const void*),
8606bfebdeSXin LI |		        bool (*const prev)(FORM*,FIELD*,const void*),
8706bfebdeSXin LI |                       void (*freecallback)(void*))
8806bfebdeSXin LI |
8906bfebdeSXin LI |   Description   :  Create a new fieldtype. The application programmer must
9006bfebdeSXin LI |                    write a field_check and a char_check function and give
9106bfebdeSXin LI |                    them as input to this call. A callback to allow the
9206bfebdeSXin LI |                    release of the allocated memory must also be provided.
9306bfebdeSXin LI |                    For generic field types, we provide some more
9406bfebdeSXin LI |                    information about the field as parameters.
9506bfebdeSXin LI |
9606bfebdeSXin LI |                    If an error occurs, errno is set to
9706bfebdeSXin LI |                       E_BAD_ARGUMENT  - invalid arguments
9806bfebdeSXin LI |                       E_SYSTEM_ERROR  - system error (no memory)
9906bfebdeSXin LI |
10006bfebdeSXin LI |   Return Values :  Fieldtype pointer or NULL if error occurred
10106bfebdeSXin LI +--------------------------------------------------------------------------*/
10206bfebdeSXin LI NCURSES_EXPORT(FIELDTYPE *)
10306bfebdeSXin LI _nc_generic_fieldtype(bool (*const field_check) (FORM *, FIELD *, const void *),
10406bfebdeSXin LI 		      bool (*const char_check) (int, FORM *, FIELD *, const
10506bfebdeSXin LI 						void *),
10606bfebdeSXin LI 		      bool (*const next) (FORM *, FIELD *, const void *),
10706bfebdeSXin LI 		      bool (*const prev) (FORM *, FIELD *, const void *),
10806bfebdeSXin LI 		      void (*freecallback) (void *))
10906bfebdeSXin LI {
11006bfebdeSXin LI   int code = E_SYSTEM_ERROR;
11106bfebdeSXin LI   FIELDTYPE *res = (FIELDTYPE *)0;
11206bfebdeSXin LI 
113aae38d10SBaptiste Daroussin   TR_FUNC_BFR(5);
114aae38d10SBaptiste Daroussin 
115aae38d10SBaptiste Daroussin   T((T_CALLED("_nc_generic_fieldtype(%s,%s,%s,%s,%s)"),
116aae38d10SBaptiste Daroussin      TR_FUNC_ARG(0, field_check),
117aae38d10SBaptiste Daroussin      TR_FUNC_ARG(1, char_check),
118aae38d10SBaptiste Daroussin      TR_FUNC_ARG(2, next),
119aae38d10SBaptiste Daroussin      TR_FUNC_ARG(3, prev),
120aae38d10SBaptiste Daroussin      TR_FUNC_ARG(4, freecallback)));
12106bfebdeSXin LI 
12206bfebdeSXin LI   if (field_check || char_check)
12306bfebdeSXin LI     {
12406bfebdeSXin LI       res = typeMalloc(FIELDTYPE, 1);
12506bfebdeSXin LI 
12606bfebdeSXin LI       if (res)
12706bfebdeSXin LI 	{
12806bfebdeSXin LI 	  *res = *_nc_Default_FieldType;
12973f0a83dSXin LI 	  SetStatus(res, (_HAS_ARGS | _GENERIC));
13006bfebdeSXin LI 	  res->fieldcheck.gfcheck = field_check;
13106bfebdeSXin LI 	  res->charcheck.gccheck = char_check;
13206bfebdeSXin LI 	  res->genericarg = Generic_This_Type;
13306bfebdeSXin LI 	  res->freearg = freecallback;
13406bfebdeSXin LI 	  res->enum_next.gnext = next;
13506bfebdeSXin LI 	  res->enum_prev.gprev = prev;
13606bfebdeSXin LI 	  code = E_OK;
13706bfebdeSXin LI 	}
13806bfebdeSXin LI     }
13906bfebdeSXin LI   else
14006bfebdeSXin LI     code = E_BAD_ARGUMENT;
14106bfebdeSXin LI 
14206bfebdeSXin LI   if (E_OK != code)
14306bfebdeSXin LI     SET_ERROR(code);
14406bfebdeSXin LI 
14506bfebdeSXin LI   returnFieldType(res);
14606bfebdeSXin LI }
14706bfebdeSXin LI 
14806bfebdeSXin LI /*---------------------------------------------------------------------------
14906bfebdeSXin LI |   Facility      :  libnform
15006bfebdeSXin LI |   Function      :  static TypeArgument *GenericArgument(
15106bfebdeSXin LI |                      const FIELDTYPE* typ,
15206bfebdeSXin LI |                      int (*argiterator)(void**),
15306bfebdeSXin LI |                      int* err)
15406bfebdeSXin LI |
15506bfebdeSXin LI |   Description   :  The iterator callback must browse through all fieldtype
15606bfebdeSXin LI |                    parameters that have an argument associated with the
15706bfebdeSXin LI |                    type. The iterator returns 1 if the operation to get
158aae38d10SBaptiste Daroussin |                    the next element was successful, 0 otherwise. If the
15906bfebdeSXin LI |                    iterator could move to the next argument, it fills
16006bfebdeSXin LI |                    the void* pointer representing the argument into the
16106bfebdeSXin LI |                    location provided as argument to the iterator.
16206bfebdeSXin LI |                    The err reference is used to keep track of errors.
16306bfebdeSXin LI |
16406bfebdeSXin LI |   Return Values :  Pointer to argument structure
16506bfebdeSXin LI +--------------------------------------------------------------------------*/
16606bfebdeSXin LI static TypeArgument *
16706bfebdeSXin LI GenericArgument(const FIELDTYPE *typ,
16806bfebdeSXin LI 		int (*argiterator) (void **), int *err)
16906bfebdeSXin LI {
17006bfebdeSXin LI   TypeArgument *res = (TypeArgument *)0;
17106bfebdeSXin LI 
17206bfebdeSXin LI   if (typ != 0 && (typ->status & _HAS_ARGS) != 0 && err != 0 && argiterator != 0)
17306bfebdeSXin LI     {
17406bfebdeSXin LI       if (typ->status & _LINKED_TYPE)
17506bfebdeSXin LI 	{
17606bfebdeSXin LI 	  /* Composite fieldtypes keep track internally of their own memory */
17706bfebdeSXin LI 	  TypeArgument *p = typeMalloc(TypeArgument, 1);
17806bfebdeSXin LI 
17906bfebdeSXin LI 	  if (p)
18006bfebdeSXin LI 	    {
18106bfebdeSXin LI 	      p->left = GenericArgument(typ->left, argiterator, err);
18206bfebdeSXin LI 	      p->right = GenericArgument(typ->right, argiterator, err);
18306bfebdeSXin LI 	      return p;
18406bfebdeSXin LI 	    }
18506bfebdeSXin LI 	  else
18606bfebdeSXin LI 	    *err += 1;
18706bfebdeSXin LI 	}
18806bfebdeSXin LI       else
18906bfebdeSXin LI 	{
19006bfebdeSXin LI 	  assert(typ->genericarg != (void *)0);
19106bfebdeSXin LI 	  if (typ->genericarg == 0)
19206bfebdeSXin LI 	    *err += 1;
19306bfebdeSXin LI 	  else
19406bfebdeSXin LI 	    {
19506bfebdeSXin LI 	      void *argp;
19606bfebdeSXin LI 	      int valid = argiterator(&argp);
19706bfebdeSXin LI 
19806bfebdeSXin LI 	      if (valid == 0 || argp == 0 ||
19906bfebdeSXin LI 		  !(res = (TypeArgument *)typ->genericarg(argp)))
20006bfebdeSXin LI 		{
20106bfebdeSXin LI 		  *err += 1;
20206bfebdeSXin LI 		}
20306bfebdeSXin LI 	    }
20406bfebdeSXin LI 	}
20506bfebdeSXin LI     }
20606bfebdeSXin LI   return res;
20706bfebdeSXin LI }
20806bfebdeSXin LI 
20906bfebdeSXin LI /*---------------------------------------------------------------------------
21006bfebdeSXin LI |   Facility      :  libnform
21106bfebdeSXin LI |   Function      :  int _nc_set_generic_fieldtype(
21206bfebdeSXin LI |                      FIELD* field,
21306bfebdeSXin LI |                      FIELDTYPE* ftyp,
21406bfebdeSXin LI |                      int (*argiterator)(void**))
21506bfebdeSXin LI |
21606bfebdeSXin LI |   Description   :  Assign the fieldtype to the field and use the iterator
21706bfebdeSXin LI |                    mechanism to get the arguments when a check is
21806bfebdeSXin LI |                    performed.
21906bfebdeSXin LI |
22006bfebdeSXin LI |   Return Values :  E_OK if all went well
22106bfebdeSXin LI |                    E_SYSTEM_ERROR if an error occurred
22206bfebdeSXin LI +--------------------------------------------------------------------------*/
22306bfebdeSXin LI NCURSES_EXPORT(int)
22406bfebdeSXin LI _nc_set_generic_fieldtype(FIELD *field,
22506bfebdeSXin LI 			  FIELDTYPE *ftyp,
22606bfebdeSXin LI 			  int (*argiterator) (void **))
22706bfebdeSXin LI {
22806bfebdeSXin LI   int code = E_SYSTEM_ERROR;
22906bfebdeSXin LI   int err = 0;
23006bfebdeSXin LI 
23106bfebdeSXin LI   if (field)
23206bfebdeSXin LI     {
23306bfebdeSXin LI       if (field && field->type)
23406bfebdeSXin LI 	_nc_Free_Type(field);
23506bfebdeSXin LI 
23606bfebdeSXin LI       field->type = ftyp;
23706bfebdeSXin LI       if (ftyp)
23806bfebdeSXin LI 	{
23906bfebdeSXin LI 	  if (argiterator)
24006bfebdeSXin LI 	    {
24106bfebdeSXin LI 	      /* The precondition is that the iterator is reset */
24206bfebdeSXin LI 	      field->arg = (void *)GenericArgument(field->type, argiterator, &err);
24306bfebdeSXin LI 
24406bfebdeSXin LI 	      if (err)
24506bfebdeSXin LI 		{
24606bfebdeSXin LI 		  _nc_Free_Argument(field->type, (TypeArgument *)(field->arg));
24706bfebdeSXin LI 		  field->type = (FIELDTYPE *)0;
24806bfebdeSXin LI 		  field->arg = (void *)0;
24906bfebdeSXin LI 		}
25006bfebdeSXin LI 	      else
25106bfebdeSXin LI 		{
25206bfebdeSXin LI 		  code = E_OK;
25306bfebdeSXin LI 		  if (field->type)
25406bfebdeSXin LI 		    field->type->ref++;
25506bfebdeSXin LI 		}
25606bfebdeSXin LI 	    }
25706bfebdeSXin LI 	}
25806bfebdeSXin LI       else
25906bfebdeSXin LI 	{
26006bfebdeSXin LI 	  field->arg = (void *)0;
26106bfebdeSXin LI 	  code = E_OK;
26206bfebdeSXin LI 	}
26306bfebdeSXin LI     }
26406bfebdeSXin LI   return code;
26506bfebdeSXin LI }
26606bfebdeSXin LI 
26706bfebdeSXin LI /*---------------------------------------------------------------------------
26806bfebdeSXin LI |   Facility      :  libnform
26906bfebdeSXin LI |   Function      :  WINDOW* _nc_form_cursor(
27006bfebdeSXin LI |                      FORM* form,
27106bfebdeSXin LI |                      int *pRow, int *pCol)
27206bfebdeSXin LI |
27306bfebdeSXin LI |   Description   :  Get the current position of the form cursor position
27406bfebdeSXin LI |                    We also return the field window
27506bfebdeSXin LI |
27606bfebdeSXin LI |   Return Values :  The fields Window or NULL on error
27706bfebdeSXin LI +--------------------------------------------------------------------------*/
27806bfebdeSXin LI NCURSES_EXPORT(WINDOW *)
27906bfebdeSXin LI _nc_form_cursor(const FORM *form, int *pRow, int *pCol)
28006bfebdeSXin LI {
28106bfebdeSXin LI   int code = E_SYSTEM_ERROR;
28206bfebdeSXin LI   WINDOW *res = (WINDOW *)0;
28306bfebdeSXin LI 
28406bfebdeSXin LI   if (!(form == 0 || pRow == 0 || pCol == 0))
28506bfebdeSXin LI     {
28606bfebdeSXin LI       *pRow = form->currow;
28706bfebdeSXin LI       *pCol = form->curcol;
28806bfebdeSXin LI       res = form->w;
28906bfebdeSXin LI       code = E_OK;
29006bfebdeSXin LI     }
29106bfebdeSXin LI   if (code != E_OK)
29206bfebdeSXin LI     SET_ERROR(code);
29306bfebdeSXin LI   return res;
29406bfebdeSXin LI }
29506bfebdeSXin LI 
29606bfebdeSXin LI #else
29706bfebdeSXin LI extern void _nc_fty_generic(void);
29806bfebdeSXin LI void
29906bfebdeSXin LI _nc_fty_generic(void)
30006bfebdeSXin LI {
30106bfebdeSXin LI }
30206bfebdeSXin LI #endif
30306bfebdeSXin LI 
30406bfebdeSXin LI /* fty_generic.c ends here */
305