fty_enum.c revision 66963
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 16MODULE_ID("$Id: fty_enum.c,v 1.13 2000/09/10 00:55:26 juergen Exp $") 17 18typedef 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+--------------------------------------------------------------------------*/ 33static void *Make_Enum_Type(va_list * ap) 34{ 35 enumARG *argp = (enumARG *)malloc(sizeof(enumARG)); 36 37 if (argp) 38 { 39 int cnt = 0; 40 char **kp = (char **)0; 41 int ccase, cunique; 42 43 argp->kwds = va_arg(*ap,char **); 44 ccase = va_arg(*ap,int); 45 cunique = va_arg(*ap,int); 46 argp->checkcase = ccase ? TRUE : FALSE; 47 argp->checkunique = cunique ? TRUE : FALSE; 48 49 kp = argp->kwds; 50 while( (kp && *kp++) ) cnt++; 51 argp->count = cnt; 52 } 53 return (void *)argp; 54} 55 56/*--------------------------------------------------------------------------- 57| Facility : libnform 58| Function : static void *Copy_Enum_Type( const void * argp ) 59| 60| Description : Copy structure for enumeration type argument. 61| 62| Return Values : Pointer to argument structure or NULL on error. 63+--------------------------------------------------------------------------*/ 64static void *Copy_Enum_Type(const void * argp) 65{ 66 enumARG *result = (enumARG *)0; 67 68 if (argp) 69 { 70 const enumARG *ap = (const enumARG *)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+--------------------------------------------------------------------------*/ 87static 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+--------------------------------------------------------------------------*/ 111static 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+--------------------------------------------------------------------------*/ 161static 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( kwds && (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( kwds && (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 203static 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+--------------------------------------------------------------------------*/ 215static 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 if (kwds) { 224 while(cnt--) 225 { 226 if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT) 227 break; 228 } 229 if (cnt<=0) 230 kwds = args->kwds; 231 if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT)) 232 { 233 set_field_buffer(field,0,*kwds); 234 return TRUE; 235 } 236 } 237 return FALSE; 238} 239 240/*--------------------------------------------------------------------------- 241| Facility : libnform 242| Function : static bool Previous_Enum( 243| FIELD * field, 244| const void * argp) 245| 246| Description : Check for the previous enumeration value 247| 248| Return Values : TRUE - previous value found and loaded 249| FALSE - no previous value loaded 250+--------------------------------------------------------------------------*/ 251static bool Previous_Enum(FIELD * field, const void * argp) 252{ 253 const enumARG *args = (const enumARG *)argp; 254 int cnt = args->count; 255 char **kwds = &args->kwds[cnt-1]; 256 bool ccase = args->checkcase; 257 unsigned char *bp = (unsigned char *)field_buffer(field,0); 258 259 if (kwds) { 260 while(cnt--) 261 { 262 if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT) 263 break; 264 } 265 266 if (cnt<=0) 267 kwds = &args->kwds[args->count-1]; 268 269 if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT)) 270 { 271 set_field_buffer(field,0,*kwds); 272 return TRUE; 273 } 274 } 275 return FALSE; 276} 277 278 279static FIELDTYPE typeENUM = { 280 _HAS_ARGS | _HAS_CHOICE | _RESIDENT, 281 1, /* this is mutable, so we can't be const */ 282 (FIELDTYPE *)0, 283 (FIELDTYPE *)0, 284 Make_Enum_Type, 285 Copy_Enum_Type, 286 Free_Enum_Type, 287 Check_Enum_Field, 288 NULL, 289 Next_Enum, 290 Previous_Enum 291}; 292 293FIELDTYPE* TYPE_ENUM = &typeENUM; 294 295/* fty_enum.c ends here */ 296