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