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