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