1/**************************************************************************** 2 * Copyright (c) 1998-2006,2007 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.22 2007/10/13 19:32:26 tom Exp $") 38 39typedef struct 40 { 41 char **kwds; 42 int count; 43 bool checkcase; 44 bool checkunique; 45 } 46enumARG; 47 48/*--------------------------------------------------------------------------- 49| Facility : libnform 50| Function : static void *Make_Enum_Type( va_list * ap ) 51| 52| Description : Allocate structure for enumeration type argument. 53| 54| Return Values : Pointer to argument structure or NULL on error 55+--------------------------------------------------------------------------*/ 56static void * 57Make_Enum_Type(va_list *ap) 58{ 59 enumARG *argp = typeMalloc(enumARG, 1); 60 61 if (argp) 62 { 63 int cnt = 0; 64 char **kp = (char **)0; 65 int ccase, cunique; 66 67 T((T_CREATE("enumARG %p"), argp)); 68 argp->kwds = va_arg(*ap, char **); 69 ccase = va_arg(*ap, int); 70 cunique = va_arg(*ap, int); 71 72 argp->checkcase = ccase ? TRUE : FALSE; 73 argp->checkunique = cunique ? TRUE : FALSE; 74 75 kp = argp->kwds; 76 while (kp && (*kp++)) 77 cnt++; 78 argp->count = cnt; 79 } 80 return (void *)argp; 81} 82 83/*--------------------------------------------------------------------------- 84| Facility : libnform 85| Function : static void *Copy_Enum_Type( const void * argp ) 86| 87| Description : Copy structure for enumeration type argument. 88| 89| Return Values : Pointer to argument structure or NULL on error. 90+--------------------------------------------------------------------------*/ 91static void * 92Copy_Enum_Type(const void *argp) 93{ 94 enumARG *result = (enumARG *)0; 95 96 if (argp) 97 { 98 const enumARG *ap = (const enumARG *)argp; 99 100 result = typeMalloc(enumARG, 1); 101 102 if (result) 103 { 104 T((T_CREATE("enumARG %p"), result)); 105 *result = *ap; 106 } 107 } 108 return (void *)result; 109} 110 111/*--------------------------------------------------------------------------- 112| Facility : libnform 113| Function : static void Free_Enum_Type( void * argp ) 114| 115| Description : Free structure for enumeration type argument. 116| 117| Return Values : - 118+--------------------------------------------------------------------------*/ 119static void 120Free_Enum_Type(void *argp) 121{ 122 if (argp) 123 free(argp); 124} 125 126#define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++ 127#define NOMATCH 0 128#define PARTIAL 1 129#define EXACT 2 130 131/*--------------------------------------------------------------------------- 132| Facility : libnform 133| Function : static int Compare(const unsigned char * s, 134| const unsigned char * buf, 135| bool ccase ) 136| 137| Description : Check whether or not the text in 'buf' matches the 138| text in 's', at least partial. 139| 140| Return Values : NOMATCH - buffer doesn't match 141| PARTIAL - buffer matches partially 142| EXACT - buffer matches exactly 143+--------------------------------------------------------------------------*/ 144static int 145Compare(const unsigned char *s, const unsigned char *buf, 146 bool ccase) 147{ 148 SKIP_SPACE(buf); /* Skip leading spaces in both texts */ 149 SKIP_SPACE(s); 150 151 if (*buf == '\0') 152 { 153 return (((*s) != '\0') ? NOMATCH : EXACT); 154 } 155 else 156 { 157 if (ccase) 158 { 159 while (*s++ == *buf) 160 { 161 if (*buf++ == '\0') 162 return EXACT; 163 } 164 } 165 else 166 { 167 while (toupper(*s++) == toupper(*buf)) 168 { 169 if (*buf++ == '\0') 170 return EXACT; 171 } 172 } 173 } 174 /* At this location buf points to the first character where it no longer 175 matches with s. So if only blanks are following, we have a partial 176 match otherwise there is no match */ 177 SKIP_SPACE(buf); 178 if (*buf) 179 return NOMATCH; 180 181 /* If it happens that the reference buffer is at its end, the partial 182 match is actually an exact match. */ 183 return ((s[-1] != '\0') ? PARTIAL : EXACT); 184} 185 186/*--------------------------------------------------------------------------- 187| Facility : libnform 188| Function : static bool Check_Enum_Field( 189| FIELD * field, 190| const void * argp) 191| 192| Description : Validate buffer content to be a valid enumeration value 193| 194| Return Values : TRUE - field is valid 195| FALSE - field is invalid 196+--------------------------------------------------------------------------*/ 197static bool 198Check_Enum_Field(FIELD *field, const void *argp) 199{ 200 char **kwds = ((const enumARG *)argp)->kwds; 201 bool ccase = ((const enumARG *)argp)->checkcase; 202 bool unique = ((const enumARG *)argp)->checkunique; 203 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 204 char *s, *t, *p; 205 int res; 206 207 while (kwds && (s = (*kwds++))) 208 { 209 if ((res = Compare((unsigned char *)s, bp, ccase)) != NOMATCH) 210 { 211 p = t = s; /* t is at least a partial match */ 212 if ((unique && res != EXACT)) 213 { 214 while (kwds && (p = *kwds++)) 215 { 216 if ((res = Compare((unsigned char *)p, bp, ccase)) != NOMATCH) 217 { 218 if (res == EXACT) 219 { 220 t = p; 221 break; 222 } 223 else 224 t = (char *)0; 225 } 226 } 227 } 228 if (t) 229 { 230 set_field_buffer(field, 0, t); 231 return TRUE; 232 } 233 if (!p) 234 break; 235 } 236 } 237 return FALSE; 238} 239 240static const char *dummy[] = 241{(char *)0}; 242 243/*--------------------------------------------------------------------------- 244| Facility : libnform 245| Function : static bool Next_Enum(FIELD * field, 246| const void * argp) 247| 248| Description : Check for the next enumeration value 249| 250| Return Values : TRUE - next value found and loaded 251| FALSE - no next value loaded 252+--------------------------------------------------------------------------*/ 253static bool 254Next_Enum(FIELD *field, const void *argp) 255{ 256 const enumARG *args = (const enumARG *)argp; 257 char **kwds = args->kwds; 258 bool ccase = args->checkcase; 259 int cnt = args->count; 260 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 261 262 if (kwds) 263 { 264 while (cnt--) 265 { 266 if (Compare((unsigned char *)(*kwds++), bp, ccase) == EXACT) 267 break; 268 } 269 if (cnt <= 0) 270 kwds = args->kwds; 271 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT)) 272 { 273 set_field_buffer(field, 0, *kwds); 274 return TRUE; 275 } 276 } 277 return FALSE; 278} 279 280/*--------------------------------------------------------------------------- 281| Facility : libnform 282| Function : static bool Previous_Enum( 283| FIELD * field, 284| const void * argp) 285| 286| Description : Check for the previous enumeration value 287| 288| Return Values : TRUE - previous value found and loaded 289| FALSE - no previous value loaded 290+--------------------------------------------------------------------------*/ 291static bool 292Previous_Enum(FIELD *field, const void *argp) 293{ 294 const enumARG *args = (const enumARG *)argp; 295 int cnt = args->count; 296 char **kwds = &args->kwds[cnt - 1]; 297 bool ccase = args->checkcase; 298 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 299 300 if (kwds) 301 { 302 while (cnt--) 303 { 304 if (Compare((unsigned char *)(*kwds--), bp, ccase) == EXACT) 305 break; 306 } 307 308 if (cnt <= 0) 309 kwds = &args->kwds[args->count - 1]; 310 311 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT)) 312 { 313 set_field_buffer(field, 0, *kwds); 314 return TRUE; 315 } 316 } 317 return FALSE; 318} 319 320static FIELDTYPE typeENUM = 321{ 322 _HAS_ARGS | _HAS_CHOICE | _RESIDENT, 323 1, /* this is mutable, so we can't be const */ 324 (FIELDTYPE *)0, 325 (FIELDTYPE *)0, 326 Make_Enum_Type, 327 Copy_Enum_Type, 328 Free_Enum_Type, 329 Check_Enum_Field, 330 NULL, 331 Next_Enum, 332 Previous_Enum 333}; 334 335NCURSES_EXPORT_VAR(FIELDTYPE *) 336TYPE_ENUM = &typeENUM; 337 338/* fty_enum.c ends here */ 339