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.15 2000/12/09 23:46:12 tom 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 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 +--------------------------------------------------------------------------*/ 64 static 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 +--------------------------------------------------------------------------*/ 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( 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 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 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 +--------------------------------------------------------------------------*/ 251 static 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 279 static 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 293 NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_ENUM = &typeENUM; 294 295 /* fty_enum.c ends here */ 296