1 /* $OpenBSD: fty_enum.c,v 1.9 2001/01/22 18:02:17 millert Exp $ */ 2 3 4 /* 5 * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. 6 * You may freely copy it for use as a template for your own field types. 7 * If you develop a field type that might be of general use, please send 8 * it back to the ncurses maintainers for inclusion in the next version. 9 */ 10 /*************************************************************************** 11 * * 12 * Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * 13 * * 14 ***************************************************************************/ 15 16 #include "form.priv.h" 17 18 MODULE_ID("$From: fty_enum.c,v 1.15 2000/12/09 23:46:12 tom Exp $") 19 20 typedef struct { 21 char **kwds; 22 int count; 23 bool checkcase; 24 bool checkunique; 25 } enumARG; 26 27 /*--------------------------------------------------------------------------- 28 | Facility : libnform 29 | Function : static void *Make_Enum_Type( va_list * ap ) 30 | 31 | Description : Allocate structure for enumeration type argument. 32 | 33 | Return Values : Pointer to argument structure or NULL on error 34 +--------------------------------------------------------------------------*/ 35 static void *Make_Enum_Type(va_list * ap) 36 { 37 enumARG *argp = (enumARG *)malloc(sizeof(enumARG)); 38 39 if (argp) 40 { 41 int cnt = 0; 42 char **kp = (char **)0; 43 int ccase, cunique; 44 45 argp->kwds = va_arg(*ap,char **); 46 ccase = va_arg(*ap,int); 47 cunique = va_arg(*ap,int); 48 argp->checkcase = ccase ? TRUE : FALSE; 49 argp->checkunique = cunique ? TRUE : FALSE; 50 51 kp = argp->kwds; 52 while( kp && (*kp++) ) cnt++; 53 argp->count = cnt; 54 } 55 return (void *)argp; 56 } 57 58 /*--------------------------------------------------------------------------- 59 | Facility : libnform 60 | Function : static void *Copy_Enum_Type( const void * argp ) 61 | 62 | Description : Copy structure for enumeration type argument. 63 | 64 | Return Values : Pointer to argument structure or NULL on error. 65 +--------------------------------------------------------------------------*/ 66 static void *Copy_Enum_Type(const void * argp) 67 { 68 enumARG *result = (enumARG *)0; 69 70 if (argp) 71 { 72 const enumARG *ap = (const enumARG *)argp; 73 74 result = (enumARG *)malloc(sizeof(enumARG)); 75 if (result) 76 *result = *ap; 77 } 78 return (void *)result; 79 } 80 81 /*--------------------------------------------------------------------------- 82 | Facility : libnform 83 | Function : static void Free_Enum_Type( void * argp ) 84 | 85 | Description : Free structure for enumeration type argument. 86 | 87 | Return Values : - 88 +--------------------------------------------------------------------------*/ 89 static void Free_Enum_Type(void * argp) 90 { 91 if (argp) 92 free(argp); 93 } 94 95 #define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++ 96 #define NOMATCH 0 97 #define PARTIAL 1 98 #define EXACT 2 99 100 /*--------------------------------------------------------------------------- 101 | Facility : libnform 102 | Function : static int Compare(const unsigned char * s, 103 | const unsigned char * buf, 104 | bool ccase ) 105 | 106 | Description : Check wether or not the text in 'buf' matches the 107 | text in 's', at least partial. 108 | 109 | Return Values : NOMATCH - buffer doesn't match 110 | PARTIAL - buffer matches partially 111 | EXACT - buffer matches exactly 112 +--------------------------------------------------------------------------*/ 113 static int Compare(const unsigned char *s, const unsigned char *buf, 114 bool ccase) 115 { 116 SKIP_SPACE(buf); /* Skip leading spaces in both texts */ 117 SKIP_SPACE(s); 118 119 if (*buf=='\0') 120 { 121 return (((*s)!='\0') ? NOMATCH : EXACT); 122 } 123 else 124 { 125 if (ccase) 126 { 127 while(*s++ == *buf) 128 { 129 if (*buf++=='\0') return EXACT; 130 } 131 } 132 else 133 { 134 while(toupper(*s++)==toupper(*buf)) 135 { 136 if (*buf++=='\0') return EXACT; 137 } 138 } 139 } 140 /* At this location buf points to the first character where it no longer 141 matches with s. So if only blanks are following, we have a partial 142 match otherwise there is no match */ 143 SKIP_SPACE(buf); 144 if (*buf) 145 return NOMATCH; 146 147 /* If it happens that the reference buffer is at its end, the partial 148 match is actually an exact match. */ 149 return ((s[-1]!='\0') ? PARTIAL : EXACT); 150 } 151 152 /*--------------------------------------------------------------------------- 153 | Facility : libnform 154 | Function : static bool Check_Enum_Field( 155 | FIELD * field, 156 | const void * argp) 157 | 158 | Description : Validate buffer content to be a valid enumeration value 159 | 160 | Return Values : TRUE - field is valid 161 | FALSE - field is invalid 162 +--------------------------------------------------------------------------*/ 163 static bool Check_Enum_Field(FIELD * field, const void * argp) 164 { 165 char **kwds = ((const enumARG *)argp)->kwds; 166 bool ccase = ((const enumARG *)argp)->checkcase; 167 bool unique = ((const enumARG *)argp)->checkunique; 168 unsigned char *bp = (unsigned char *)field_buffer(field,0); 169 char *s, *t, *p; 170 int res; 171 172 while( kwds && (s=(*kwds++)) ) 173 { 174 if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH) 175 { 176 p=t=s; /* t is at least a partial match */ 177 if ((unique && res!=EXACT)) 178 { 179 while( kwds && (p = *kwds++) ) 180 { 181 if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH) 182 { 183 if (res==EXACT) 184 { 185 t = p; 186 break; 187 } 188 else 189 t = (char *)0; 190 } 191 } 192 } 193 if (t) 194 { 195 set_field_buffer(field,0,t); 196 return TRUE; 197 } 198 if (!p) 199 break; 200 } 201 } 202 return FALSE; 203 } 204 205 static const char *dummy[] = { (char *)0 }; 206 207 /*--------------------------------------------------------------------------- 208 | Facility : libnform 209 | Function : static bool Next_Enum(FIELD * field, 210 | const void * argp) 211 | 212 | Description : Check for the next enumeration value 213 | 214 | Return Values : TRUE - next value found and loaded 215 | FALSE - no next value loaded 216 +--------------------------------------------------------------------------*/ 217 static bool Next_Enum(FIELD * field, const void * argp) 218 { 219 const enumARG *args = (const enumARG *)argp; 220 char **kwds = args->kwds; 221 bool ccase = args->checkcase; 222 int cnt = args->count; 223 unsigned char *bp = (unsigned char *)field_buffer(field,0); 224 225 if (kwds) { 226 while(cnt--) 227 { 228 if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT) 229 break; 230 } 231 if (cnt<=0) 232 kwds = args->kwds; 233 if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT)) 234 { 235 set_field_buffer(field,0,*kwds); 236 return TRUE; 237 } 238 } 239 return FALSE; 240 } 241 242 /*--------------------------------------------------------------------------- 243 | Facility : libnform 244 | Function : static bool Previous_Enum( 245 | FIELD * field, 246 | const void * argp) 247 | 248 | Description : Check for the previous enumeration value 249 | 250 | Return Values : TRUE - previous value found and loaded 251 | FALSE - no previous value loaded 252 +--------------------------------------------------------------------------*/ 253 static bool Previous_Enum(FIELD * field, const void * argp) 254 { 255 const enumARG *args = (const enumARG *)argp; 256 int cnt = args->count; 257 char **kwds = &args->kwds[cnt-1]; 258 bool ccase = args->checkcase; 259 unsigned char *bp = (unsigned char *)field_buffer(field,0); 260 261 if (kwds) { 262 while(cnt--) 263 { 264 if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT) 265 break; 266 } 267 268 if (cnt<=0) 269 kwds = &args->kwds[args->count-1]; 270 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 static FIELDTYPE typeENUM = { 282 _HAS_ARGS | _HAS_CHOICE | _RESIDENT, 283 1, /* this is mutable, so we can't be const */ 284 (FIELDTYPE *)0, 285 (FIELDTYPE *)0, 286 Make_Enum_Type, 287 Copy_Enum_Type, 288 Free_Enum_Type, 289 Check_Enum_Field, 290 NULL, 291 Next_Enum, 292 Previous_Enum 293 }; 294 295 NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_ENUM = &typeENUM; 296 297 /* fty_enum.c ends here */ 298