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 37MODULE_ID("$Id: fty_enum.c,v 1.26 2010/05/01 21:11:07 tom Exp $") 38 39typedef struct 40 { 41 char **kwds; 42 int count; 43 bool checkcase; 44 bool checkunique; 45 } 46enumARG; 47 48typedef struct 49 { 50 char **kwds; 51 int ccase; 52 int cunique; 53 } 54enumParams; 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+--------------------------------------------------------------------------*/ 64static void * 65Generic_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+--------------------------------------------------------------------------*/ 127static void * 128Make_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+--------------------------------------------------------------------------*/ 147static void * 148Copy_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+--------------------------------------------------------------------------*/ 191static void 192Free_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+--------------------------------------------------------------------------*/ 233static int 234Compare(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+--------------------------------------------------------------------------*/ 286static bool 287Check_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 329static 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+--------------------------------------------------------------------------*/ 342static bool 343Next_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+--------------------------------------------------------------------------*/ 380static bool 381Previous_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 409static 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 427NCURSES_EXPORT_VAR(FIELDTYPE *) 428TYPE_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*/ 435NCURSES_EXPORT(FIELDTYPE *) 436_nc_TYPE_ENUM(void) 437{ 438 return TYPE_ENUM; 439} 440#endif 441 442/* fty_enum.c ends here */ 443