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