1 /**************************************************************************** 2 * Copyright (c) 2008-2018,2020 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.9 2020/01/18 17:08:04 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 TR_FUNC_BFR(5); 113 114 T((T_CALLED("_nc_generic_fieldtype(%s,%s,%s,%s,%s)"), 115 TR_FUNC_ARG(0, field_check), 116 TR_FUNC_ARG(1, char_check), 117 TR_FUNC_ARG(2, next), 118 TR_FUNC_ARG(3, prev), 119 TR_FUNC_ARG(4, freecallback))); 120 121 if (field_check || char_check) 122 { 123 res = typeMalloc(FIELDTYPE, 1); 124 125 if (res) 126 { 127 *res = *_nc_Default_FieldType; 128 SetStatus(res, (_HAS_ARGS | _GENERIC)); 129 res->fieldcheck.gfcheck = field_check; 130 res->charcheck.gccheck = char_check; 131 res->genericarg = Generic_This_Type; 132 res->freearg = freecallback; 133 res->enum_next.gnext = next; 134 res->enum_prev.gprev = prev; 135 code = E_OK; 136 } 137 } 138 else 139 code = E_BAD_ARGUMENT; 140 141 if (E_OK != code) 142 SET_ERROR(code); 143 144 returnFieldType(res); 145 } 146 147 /*--------------------------------------------------------------------------- 148 | Facility : libnform 149 | Function : static TypeArgument *GenericArgument( 150 | const FIELDTYPE* typ, 151 | int (*argiterator)(void**), 152 | int* err) 153 | 154 | Description : The iterator callback must browse through all fieldtype 155 | parameters that have an argument associated with the 156 | type. The iterator returns 1 if the operation to get 157 | the next element was successful, 0 otherwise. If the 158 | iterator could move to the next argument, it fills 159 | the void* pointer representing the argument into the 160 | location provided as argument to the iterator. 161 | The err reference is used to keep track of errors. 162 | 163 | Return Values : Pointer to argument structure 164 +--------------------------------------------------------------------------*/ 165 static TypeArgument * 166 GenericArgument(const FIELDTYPE *typ, 167 int (*argiterator) (void **), int *err) 168 { 169 TypeArgument *res = (TypeArgument *)0; 170 171 if (typ != 0 && (typ->status & _HAS_ARGS) != 0 && err != 0 && argiterator != 0) 172 { 173 if (typ->status & _LINKED_TYPE) 174 { 175 /* Composite fieldtypes keep track internally of their own memory */ 176 TypeArgument *p = typeMalloc(TypeArgument, 1); 177 178 if (p) 179 { 180 p->left = GenericArgument(typ->left, argiterator, err); 181 p->right = GenericArgument(typ->right, argiterator, err); 182 return p; 183 } 184 else 185 *err += 1; 186 } 187 else 188 { 189 assert(typ->genericarg != (void *)0); 190 if (typ->genericarg == 0) 191 *err += 1; 192 else 193 { 194 void *argp; 195 int valid = argiterator(&argp); 196 197 if (valid == 0 || argp == 0 || 198 !(res = (TypeArgument *)typ->genericarg(argp))) 199 { 200 *err += 1; 201 } 202 } 203 } 204 } 205 return res; 206 } 207 208 /*--------------------------------------------------------------------------- 209 | Facility : libnform 210 | Function : int _nc_set_generic_fieldtype( 211 | FIELD* field, 212 | FIELDTYPE* ftyp, 213 | int (*argiterator)(void**)) 214 | 215 | Description : Assign the fieldtype to the field and use the iterator 216 | mechanism to get the arguments when a check is 217 | performed. 218 | 219 | Return Values : E_OK if all went well 220 | E_SYSTEM_ERROR if an error occurred 221 +--------------------------------------------------------------------------*/ 222 NCURSES_EXPORT(int) 223 _nc_set_generic_fieldtype(FIELD *field, 224 FIELDTYPE *ftyp, 225 int (*argiterator) (void **)) 226 { 227 int code = E_SYSTEM_ERROR; 228 int err = 0; 229 230 if (field) 231 { 232 if (field && field->type) 233 _nc_Free_Type(field); 234 235 field->type = ftyp; 236 if (ftyp) 237 { 238 if (argiterator) 239 { 240 /* The precondition is that the iterator is reset */ 241 field->arg = (void *)GenericArgument(field->type, argiterator, &err); 242 243 if (err) 244 { 245 _nc_Free_Argument(field->type, (TypeArgument *)(field->arg)); 246 field->type = (FIELDTYPE *)0; 247 field->arg = (void *)0; 248 } 249 else 250 { 251 code = E_OK; 252 if (field->type) 253 field->type->ref++; 254 } 255 } 256 } 257 else 258 { 259 field->arg = (void *)0; 260 code = E_OK; 261 } 262 } 263 return code; 264 } 265 266 /*--------------------------------------------------------------------------- 267 | Facility : libnform 268 | Function : WINDOW* _nc_form_cursor( 269 | FORM* form, 270 | int *pRow, int *pCol) 271 | 272 | Description : Get the current position of the form cursor position 273 | We also return the field window 274 | 275 | Return Values : The fields Window or NULL on error 276 +--------------------------------------------------------------------------*/ 277 NCURSES_EXPORT(WINDOW *) 278 _nc_form_cursor(const FORM *form, int *pRow, int *pCol) 279 { 280 int code = E_SYSTEM_ERROR; 281 WINDOW *res = (WINDOW *)0; 282 283 if (!(form == 0 || pRow == 0 || pCol == 0)) 284 { 285 *pRow = form->currow; 286 *pCol = form->curcol; 287 res = form->w; 288 code = E_OK; 289 } 290 if (code != E_OK) 291 SET_ERROR(code); 292 return res; 293 } 294 295 #else 296 extern void _nc_fty_generic(void); 297 void 298 _nc_fty_generic(void) 299 { 300 } 301 #endif 302 303 /* fty_generic.c ends here */ 304