fty_enum.c revision 62449
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.11 2000/03/19 01:09:56 Bruno.Haible 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 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+--------------------------------------------------------------------------*/ 63static 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+--------------------------------------------------------------------------*/ 85static 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+--------------------------------------------------------------------------*/ 109static 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+--------------------------------------------------------------------------*/ 159static 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 201static 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+--------------------------------------------------------------------------*/ 213static 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+--------------------------------------------------------------------------*/ 247static 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 273static 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 287FIELDTYPE* TYPE_ENUM = &typeENUM; 288 289/* fty_enum.c ends here */ 290