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 37 MODULE_ID("$Id: fty_enum.c,v 1.22 2007/10/13 19:32:26 tom Exp $") 38 39 typedef struct 40 { 41 char **kwds; 42 int count; 43 bool checkcase; 44 bool checkunique; 45 } 46 enumARG; 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 +--------------------------------------------------------------------------*/ 56 static void * 57 Make_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 +--------------------------------------------------------------------------*/ 91 static void * 92 Copy_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 +--------------------------------------------------------------------------*/ 119 static void 120 Free_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 +--------------------------------------------------------------------------*/ 144 static int 145 Compare(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 +--------------------------------------------------------------------------*/ 197 static bool 198 Check_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 240 static 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 +--------------------------------------------------------------------------*/ 253 static bool 254 Next_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 +--------------------------------------------------------------------------*/ 291 static bool 292 Previous_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 320 static 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 335 NCURSES_EXPORT_VAR(FIELDTYPE *) 336 TYPE_ENUM = &typeENUM; 337 338 /* fty_enum.c ends here */ 339