1 /**************************************************************************** 2 * Copyright (c) 1998-2009,2010 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_enum.c,v 1.26 2010/05/01 21:11:07 tom Exp $") 38 39 typedef struct 40 { 41 char **kwds; 42 int count; 43 bool checkcase; 44 bool checkunique; 45 } 46 enumARG; 47 48 typedef struct 49 { 50 char **kwds; 51 int ccase; 52 int cunique; 53 } 54 enumParams; 55 56 /*--------------------------------------------------------------------------- 57 | Facility : libnform 58 | Function : static void *Generic_Enum_Type(void * arg) 59 | 60 | Description : Allocate structure for enumeration type argument. 61 | 62 | Return Values : Pointer to argument structure or NULL on error 63 +--------------------------------------------------------------------------*/ 64 static void * 65 Generic_Enum_Type(void *arg) 66 { 67 enumARG *argp = (enumARG *)0; 68 enumParams *params = (enumParams *) arg; 69 70 if (params) 71 { 72 argp = typeMalloc(enumARG, 1); 73 74 if (argp) 75 { 76 int cnt = 0; 77 char **kp = (char **)0; 78 char **kwds = (char **)0; 79 char **kptarget; 80 int ccase, cunique; 81 82 T((T_CREATE("enumARG %p"), (void *)argp)); 83 kwds = params->kwds; 84 ccase = params->ccase; 85 cunique = params->cunique; 86 87 argp->checkcase = ccase ? TRUE : FALSE; 88 argp->checkunique = cunique ? TRUE : FALSE; 89 argp->kwds = (char **)0; 90 91 kp = kwds; 92 while (kp && (*kp++)) 93 cnt++; 94 argp->count = cnt; 95 96 if (cnt > 0) 97 { 98 /* We copy the keywords, because we can't rely on the fact 99 that the caller doesn't relocate or free the memory used 100 for the keywords (maybe he has GC) 101 */ 102 argp->kwds = typeMalloc(char *, cnt + 1); 103 104 kp = kwds; 105 if ((kptarget = argp->kwds) != 0) 106 { 107 while (kp && (*kp)) 108 { 109 (*kptarget++) = strdup(*kp++); 110 } 111 *kptarget = (char *)0; 112 } 113 } 114 } 115 } 116 return (void *)argp; 117 } 118 119 /*--------------------------------------------------------------------------- 120 | Facility : libnform 121 | Function : static void *Make_Enum_Type( va_list * ap ) 122 | 123 | Description : Allocate structure for enumeration type argument. 124 | 125 | Return Values : Pointer to argument structure or NULL on error 126 +--------------------------------------------------------------------------*/ 127 static void * 128 Make_Enum_Type(va_list *ap) 129 { 130 enumParams params; 131 132 params.kwds = va_arg(*ap, char **); 133 params.ccase = va_arg(*ap, int); 134 params.cunique = va_arg(*ap, int); 135 136 return Generic_Enum_Type((void *)¶ms); 137 } 138 139 /*--------------------------------------------------------------------------- 140 | Facility : libnform 141 | Function : static void *Copy_Enum_Type( const void * argp ) 142 | 143 | Description : Copy structure for enumeration type argument. 144 | 145 | Return Values : Pointer to argument structure or NULL on error. 146 +--------------------------------------------------------------------------*/ 147 static void * 148 Copy_Enum_Type(const void *argp) 149 { 150 enumARG *result = (enumARG *)0; 151 152 if (argp) 153 { 154 const enumARG *ap = (const enumARG *)argp; 155 156 result = typeMalloc(enumARG, 1); 157 158 if (result) 159 { 160 T((T_CREATE("enumARG %p"), (void *)result)); 161 *result = *ap; 162 163 if (ap->count > 0) 164 { 165 char **kptarget; 166 char **kp = ap->kwds; 167 result->kwds = typeMalloc(char *, 1 + ap->count); 168 169 if ((kptarget = result->kwds) != 0) 170 { 171 while (kp && (*kp)) 172 { 173 (*kptarget++) = strdup(*kp++); 174 } 175 *kptarget = (char *)0; 176 } 177 } 178 } 179 } 180 return (void *)result; 181 } 182 183 /*--------------------------------------------------------------------------- 184 | Facility : libnform 185 | Function : static void Free_Enum_Type( void * argp ) 186 | 187 | Description : Free structure for enumeration type argument. 188 | 189 | Return Values : - 190 +--------------------------------------------------------------------------*/ 191 static void 192 Free_Enum_Type(void *argp) 193 { 194 if (argp) 195 { 196 const enumARG *ap = (const enumARG *)argp; 197 198 if (ap->kwds && ap->count > 0) 199 { 200 char **kp = ap->kwds; 201 int cnt = 0; 202 203 while (kp && (*kp)) 204 { 205 free(*kp++); 206 cnt++; 207 } 208 assert(cnt == ap->count); 209 free(ap->kwds); 210 } 211 free(argp); 212 } 213 } 214 215 #define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++ 216 #define NOMATCH 0 217 #define PARTIAL 1 218 #define EXACT 2 219 220 /*--------------------------------------------------------------------------- 221 | Facility : libnform 222 | Function : static int Compare(const unsigned char * s, 223 | const unsigned char * buf, 224 | bool ccase ) 225 | 226 | Description : Check whether or not the text in 'buf' matches the 227 | text in 's', at least partial. 228 | 229 | Return Values : NOMATCH - buffer doesn't match 230 | PARTIAL - buffer matches partially 231 | EXACT - buffer matches exactly 232 +--------------------------------------------------------------------------*/ 233 static int 234 Compare(const unsigned char *s, const unsigned char *buf, 235 bool ccase) 236 { 237 SKIP_SPACE(buf); /* Skip leading spaces in both texts */ 238 SKIP_SPACE(s); 239 240 if (*buf == '\0') 241 { 242 return (((*s) != '\0') ? NOMATCH : EXACT); 243 } 244 else 245 { 246 if (ccase) 247 { 248 while (*s++ == *buf) 249 { 250 if (*buf++ == '\0') 251 return EXACT; 252 } 253 } 254 else 255 { 256 while (toupper(*s++) == toupper(*buf)) 257 { 258 if (*buf++ == '\0') 259 return EXACT; 260 } 261 } 262 } 263 /* At this location buf points to the first character where it no longer 264 matches with s. So if only blanks are following, we have a partial 265 match otherwise there is no match */ 266 SKIP_SPACE(buf); 267 if (*buf) 268 return NOMATCH; 269 270 /* If it happens that the reference buffer is at its end, the partial 271 match is actually an exact match. */ 272 return ((s[-1] != '\0') ? PARTIAL : EXACT); 273 } 274 275 /*--------------------------------------------------------------------------- 276 | Facility : libnform 277 | Function : static bool Check_Enum_Field( 278 | FIELD * field, 279 | const void * argp) 280 | 281 | Description : Validate buffer content to be a valid enumeration value 282 | 283 | Return Values : TRUE - field is valid 284 | FALSE - field is invalid 285 +--------------------------------------------------------------------------*/ 286 static bool 287 Check_Enum_Field(FIELD *field, const void *argp) 288 { 289 char **kwds = ((const enumARG *)argp)->kwds; 290 bool ccase = ((const enumARG *)argp)->checkcase; 291 bool unique = ((const enumARG *)argp)->checkunique; 292 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 293 char *s, *t, *p; 294 int res; 295 296 while (kwds && (s = (*kwds++))) 297 { 298 if ((res = Compare((unsigned char *)s, bp, ccase)) != NOMATCH) 299 { 300 p = t = s; /* t is at least a partial match */ 301 if ((unique && res != EXACT)) 302 { 303 while (kwds && (p = *kwds++)) 304 { 305 if ((res = Compare((unsigned char *)p, bp, ccase)) != NOMATCH) 306 { 307 if (res == EXACT) 308 { 309 t = p; 310 break; 311 } 312 else 313 t = (char *)0; 314 } 315 } 316 } 317 if (t) 318 { 319 set_field_buffer(field, 0, t); 320 return TRUE; 321 } 322 if (!p) 323 break; 324 } 325 } 326 return FALSE; 327 } 328 329 static const char *dummy[] = 330 {(char *)0}; 331 332 /*--------------------------------------------------------------------------- 333 | Facility : libnform 334 | Function : static bool Next_Enum(FIELD * field, 335 | const void * argp) 336 | 337 | Description : Check for the next enumeration value 338 | 339 | Return Values : TRUE - next value found and loaded 340 | FALSE - no next value loaded 341 +--------------------------------------------------------------------------*/ 342 static bool 343 Next_Enum(FIELD *field, const void *argp) 344 { 345 const enumARG *args = (const enumARG *)argp; 346 char **kwds = args->kwds; 347 bool ccase = args->checkcase; 348 int cnt = args->count; 349 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 350 351 if (kwds) 352 { 353 while (cnt--) 354 { 355 if (Compare((unsigned char *)(*kwds++), bp, ccase) == EXACT) 356 break; 357 } 358 if (cnt <= 0) 359 kwds = args->kwds; 360 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT)) 361 { 362 set_field_buffer(field, 0, *kwds); 363 return TRUE; 364 } 365 } 366 return FALSE; 367 } 368 369 /*--------------------------------------------------------------------------- 370 | Facility : libnform 371 | Function : static bool Previous_Enum( 372 | FIELD * field, 373 | const void * argp) 374 | 375 | Description : Check for the previous enumeration value 376 | 377 | Return Values : TRUE - previous value found and loaded 378 | FALSE - no previous value loaded 379 +--------------------------------------------------------------------------*/ 380 static bool 381 Previous_Enum(FIELD *field, const void *argp) 382 { 383 const enumARG *args = (const enumARG *)argp; 384 int cnt = args->count; 385 char **kwds = &args->kwds[cnt - 1]; 386 bool ccase = args->checkcase; 387 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 388 389 if (kwds) 390 { 391 while (cnt--) 392 { 393 if (Compare((unsigned char *)(*kwds--), bp, ccase) == EXACT) 394 break; 395 } 396 397 if (cnt <= 0) 398 kwds = &args->kwds[args->count - 1]; 399 400 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT)) 401 { 402 set_field_buffer(field, 0, *kwds); 403 return TRUE; 404 } 405 } 406 return FALSE; 407 } 408 409 static FIELDTYPE typeENUM = 410 { 411 _HAS_ARGS | _HAS_CHOICE | _RESIDENT, 412 1, /* this is mutable, so we can't be const */ 413 (FIELDTYPE *)0, 414 (FIELDTYPE *)0, 415 Make_Enum_Type, 416 Copy_Enum_Type, 417 Free_Enum_Type, 418 INIT_FT_FUNC(Check_Enum_Field), 419 INIT_FT_FUNC(NULL), 420 INIT_FT_FUNC(Next_Enum), 421 INIT_FT_FUNC(Previous_Enum), 422 #if NCURSES_INTEROP_FUNCS 423 Generic_Enum_Type 424 #endif 425 }; 426 427 NCURSES_EXPORT_VAR(FIELDTYPE *) 428 TYPE_ENUM = &typeENUM; 429 430 #if NCURSES_INTEROP_FUNCS 431 /* The next routines are to simplify the use of ncurses from 432 programming languages with restictions on interop with C level 433 constructs (e.g. variable access or va_list + ellipsis constructs) 434 */ 435 NCURSES_EXPORT(FIELDTYPE *) 436 _nc_TYPE_ENUM(void) 437 { 438 return TYPE_ENUM; 439 } 440 #endif 441 442 /* fty_enum.c ends here */ 443