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