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