1 /* $OpenBSD: fty_enum.c,v 1.11 2015/01/23 22:48:51 krw Exp $ */ 2 /**************************************************************************** 3 * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30 /*************************************************************************** 31 * * 32 * Author : Juergen Pfeifer * 33 * * 34 ***************************************************************************/ 35 36 #include "form.priv.h" 37 38 MODULE_ID("$Id: fty_enum.c,v 1.11 2015/01/23 22:48:51 krw Exp $") 39 40 typedef struct 41 { 42 char **kwds; 43 int count; 44 bool checkcase; 45 bool checkunique; 46 } 47 enumARG; 48 49 /*--------------------------------------------------------------------------- 50 | Facility : libnform 51 | Function : static void *Make_Enum_Type( va_list * ap ) 52 | 53 | Description : Allocate structure for enumeration type argument. 54 | 55 | Return Values : Pointer to argument structure or NULL on error 56 +--------------------------------------------------------------------------*/ 57 static void * 58 Make_Enum_Type(va_list *ap) 59 { 60 enumARG *argp = typeMalloc(enumARG, 1); 61 62 if (argp) 63 { 64 int cnt = 0; 65 char **kp = (char **)0; 66 int ccase, cunique; 67 68 T((T_CREATE("enumARG %p"), argp)); 69 argp->kwds = va_arg(*ap, char **); 70 ccase = va_arg(*ap, int); 71 cunique = va_arg(*ap, int); 72 73 argp->checkcase = ccase ? TRUE : FALSE; 74 argp->checkunique = cunique ? TRUE : FALSE; 75 76 kp = argp->kwds; 77 while (kp && (*kp++)) 78 cnt++; 79 argp->count = cnt; 80 } 81 return (void *)argp; 82 } 83 84 /*--------------------------------------------------------------------------- 85 | Facility : libnform 86 | Function : static void *Copy_Enum_Type( const void * argp ) 87 | 88 | Description : Copy structure for enumeration type argument. 89 | 90 | Return Values : Pointer to argument structure or NULL on error. 91 +--------------------------------------------------------------------------*/ 92 static void * 93 Copy_Enum_Type(const void *argp) 94 { 95 enumARG *result = (enumARG *)0; 96 97 if (argp) 98 { 99 const enumARG *ap = (const enumARG *)argp; 100 101 result = typeMalloc(enumARG, 1); 102 103 if (result) 104 { 105 T((T_CREATE("enumARG %p"), result)); 106 *result = *ap; 107 } 108 } 109 return (void *)result; 110 } 111 112 /*--------------------------------------------------------------------------- 113 | Facility : libnform 114 | Function : static void Free_Enum_Type( void * argp ) 115 | 116 | Description : Free structure for enumeration type argument. 117 | 118 | Return Values : - 119 +--------------------------------------------------------------------------*/ 120 static void 121 Free_Enum_Type(void *argp) 122 { 123 if (argp) 124 free(argp); 125 } 126 127 #define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++ 128 #define NOMATCH 0 129 #define PARTIAL 1 130 #define EXACT 2 131 132 /*--------------------------------------------------------------------------- 133 | Facility : libnform 134 | Function : static int Compare(const unsigned char * s, 135 | const unsigned char * buf, 136 | bool ccase ) 137 | 138 | Description : Check whether or not the text in 'buf' matches the 139 | text in 's', at least partial. 140 | 141 | Return Values : NOMATCH - buffer doesn't match 142 | PARTIAL - buffer matches partially 143 | EXACT - buffer matches exactly 144 +--------------------------------------------------------------------------*/ 145 static int 146 Compare(const unsigned char *s, const unsigned char *buf, 147 bool ccase) 148 { 149 SKIP_SPACE(buf); /* Skip leading spaces in both texts */ 150 SKIP_SPACE(s); 151 152 if (*buf == '\0') 153 { 154 return (((*s) != '\0') ? NOMATCH : EXACT); 155 } 156 else 157 { 158 if (ccase) 159 { 160 while (*s++ == *buf) 161 { 162 if (*buf++ == '\0') 163 return EXACT; 164 } 165 } 166 else 167 { 168 while (toupper(*s++) == toupper(*buf)) 169 { 170 if (*buf++ == '\0') 171 return EXACT; 172 } 173 } 174 } 175 /* At this location buf points to the first character where it no longer 176 matches with s. So if only blanks are following, we have a partial 177 match otherwise there is no match */ 178 SKIP_SPACE(buf); 179 if (*buf) 180 return NOMATCH; 181 182 /* If it happens that the reference buffer is at its end, the partial 183 match is actually an exact match. */ 184 return ((s[-1] != '\0') ? PARTIAL : EXACT); 185 } 186 187 /*--------------------------------------------------------------------------- 188 | Facility : libnform 189 | Function : static bool Check_Enum_Field( 190 | FIELD * field, 191 | const void * argp) 192 | 193 | Description : Validate buffer content to be a valid enumeration value 194 | 195 | Return Values : TRUE - field is valid 196 | FALSE - field is invalid 197 +--------------------------------------------------------------------------*/ 198 static bool 199 Check_Enum_Field(FIELD *field, const void *argp) 200 { 201 char **kwds = ((const enumARG *)argp)->kwds; 202 bool ccase = ((const enumARG *)argp)->checkcase; 203 bool unique = ((const enumARG *)argp)->checkunique; 204 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 205 char *s, *t, *p; 206 int res; 207 208 while (kwds && (s = (*kwds++))) 209 { 210 if ((res = Compare((unsigned char *)s, bp, ccase)) != NOMATCH) 211 { 212 p = t = s; /* t is at least a partial match */ 213 if ((unique && res != EXACT)) 214 { 215 while (kwds && (p = *kwds++)) 216 { 217 if ((res = Compare((unsigned char *)p, bp, ccase)) != NOMATCH) 218 { 219 if (res == EXACT) 220 { 221 t = p; 222 break; 223 } 224 else 225 t = (char *)0; 226 } 227 } 228 } 229 if (t) 230 { 231 set_field_buffer(field, 0, t); 232 return TRUE; 233 } 234 if (!p) 235 break; 236 } 237 } 238 return FALSE; 239 } 240 241 static const char *dummy[] = 242 {(char *)0}; 243 244 /*--------------------------------------------------------------------------- 245 | Facility : libnform 246 | Function : static bool Next_Enum(FIELD * field, 247 | const void * argp) 248 | 249 | Description : Check for the next enumeration value 250 | 251 | Return Values : TRUE - next value found and loaded 252 | FALSE - no next value loaded 253 +--------------------------------------------------------------------------*/ 254 static bool 255 Next_Enum(FIELD *field, const void *argp) 256 { 257 const enumARG *args = (const enumARG *)argp; 258 char **kwds = args->kwds; 259 bool ccase = args->checkcase; 260 int cnt = args->count; 261 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 262 263 if (kwds) 264 { 265 while (cnt--) 266 { 267 if (Compare((unsigned char *)(*kwds++), bp, ccase) == EXACT) 268 break; 269 } 270 if (cnt <= 0) 271 kwds = args->kwds; 272 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT)) 273 { 274 set_field_buffer(field, 0, *kwds); 275 return TRUE; 276 } 277 } 278 return FALSE; 279 } 280 281 /*--------------------------------------------------------------------------- 282 | Facility : libnform 283 | Function : static bool Previous_Enum( 284 | FIELD * field, 285 | const void * argp) 286 | 287 | Description : Check for the previous enumeration value 288 | 289 | Return Values : TRUE - previous value found and loaded 290 | FALSE - no previous value loaded 291 +--------------------------------------------------------------------------*/ 292 static bool 293 Previous_Enum(FIELD *field, const void *argp) 294 { 295 const enumARG *args = (const enumARG *)argp; 296 int cnt = args->count; 297 char **kwds = &args->kwds[cnt - 1]; 298 bool ccase = args->checkcase; 299 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 300 301 if (kwds) 302 { 303 while (cnt--) 304 { 305 if (Compare((unsigned char *)(*kwds--), bp, ccase) == EXACT) 306 break; 307 } 308 309 if (cnt <= 0) 310 kwds = &args->kwds[args->count - 1]; 311 312 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT)) 313 { 314 set_field_buffer(field, 0, *kwds); 315 return TRUE; 316 } 317 } 318 return FALSE; 319 } 320 321 static FIELDTYPE typeENUM = 322 { 323 _HAS_ARGS | _HAS_CHOICE | _RESIDENT, 324 1, /* this is mutable, so we can't be const */ 325 (FIELDTYPE *)0, 326 (FIELDTYPE *)0, 327 Make_Enum_Type, 328 Copy_Enum_Type, 329 Free_Enum_Type, 330 Check_Enum_Field, 331 NULL, 332 Next_Enum, 333 Previous_Enum 334 }; 335 336 NCURSES_EXPORT_VAR(FIELDTYPE *) 337 TYPE_ENUM = &typeENUM; 338 339 /* fty_enum.c ends here */ 340