| /* | |
| * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT. | |
| * You may freely copy it for use as a template for your own field types. | |
| * If you develop a field type that might be of general use, please send | |
| * it back to the ncurses maintainers for inclusion in the next version. | |
| */ | |
| /*************************************************************************** | |
| * * | |
| * Author : Juergen Pfeifer, juergen.pfeifer@gmx.net * | |
| * * | |
| ***************************************************************************/ | |
| #include "form.priv.h" | |
| MODULE_ID("$Id$") | |
| typedef struct { | |
| char **kwds; | |
| int count; | |
| bool checkcase; | |
| bool checkunique; | |
| } enumARG; | |
| /*--------------------------------------------------------------------------- | |
| | Facility : libnform | |
| | Function : static void *Make_Enum_Type( va_list * ap ) | |
| | | |
| | Description : Allocate structure for enumeration type argument. | |
| | | |
| | Return Values : Pointer to argument structure or NULL on error | |
| +--------------------------------------------------------------------------*/ | |
| static void *Make_Enum_Type(va_list * ap) | |
| { | |
| enumARG *argp = (enumARG *)malloc(sizeof(enumARG)); | |
| if (argp) | |
| { | |
| int cnt = 0; | |
| char **kp = (char **)0; | |
| int ccase, cunique; | |
| argp->kwds = va_arg(*ap,char **); | |
| ccase = va_arg(*ap,int); | |
| cunique = va_arg(*ap,int); | |
| argp->checkcase = ccase ? TRUE : FALSE; | |
| argp->checkunique = cunique ? TRUE : FALSE; | |
| kp = argp->kwds; | |
| while( kp && (*kp++) ) cnt++; | |
| argp->count = cnt; | |
| } | |
| return (void *)argp; | |
| } | |
| /*--------------------------------------------------------------------------- | |
| | Facility : libnform | |
| | Function : static void *Copy_Enum_Type( const void * argp ) | |
| | | |
| | Description : Copy structure for enumeration type argument. | |
| | | |
| | Return Values : Pointer to argument structure or NULL on error. | |
| +--------------------------------------------------------------------------*/ | |
| static void *Copy_Enum_Type(const void * argp) | |
| { | |
| enumARG *result = (enumARG *)0; | |
| if (argp) | |
| { | |
| const enumARG *ap = (const enumARG *)argp; | |
| result = (enumARG *)malloc(sizeof(enumARG)); | |
| if (result) | |
| *result = *ap; | |
| } | |
| return (void *)result; | |
| } | |
| /*--------------------------------------------------------------------------- | |
| | Facility : libnform | |
| | Function : static void Free_Enum_Type( void * argp ) | |
| | | |
| | Description : Free structure for enumeration type argument. | |
| | | |
| | Return Values : - | |
| +--------------------------------------------------------------------------*/ | |
| static void Free_Enum_Type(void * argp) | |
| { | |
| if (argp) | |
| free(argp); | |
| } | |
| #define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++ | |
| #define NOMATCH 0 | |
| #define PARTIAL 1 | |
| #define EXACT 2 | |
| /*--------------------------------------------------------------------------- | |
| | Facility : libnform | |
| | Function : static int Compare(const unsigned char * s, | |
| | const unsigned char * buf, | |
| | bool ccase ) | |
| | | |
| | Description : Check whether or not the text in 'buf' matches the | |
| | text in 's', at least partial. | |
| | | |
| | Return Values : NOMATCH - buffer doesn't match | |
| | PARTIAL - buffer matches partially | |
| | EXACT - buffer matches exactly | |
| +--------------------------------------------------------------------------*/ | |
| static int Compare(const unsigned char *s, const unsigned char *buf, | |
| bool ccase) | |
| { | |
| SKIP_SPACE(buf); /* Skip leading spaces in both texts */ | |
| SKIP_SPACE(s); | |
| if (*buf=='\0') | |
| { | |
| return (((*s)=='\0') ? EXACT : NOMATCH); | |
| } | |
| else | |
| { | |
| if (ccase) | |
| { | |
| while(*s++ == *buf) | |
| { | |
| if (*buf++=='\0') return EXACT; | |
| } | |
| } | |
| else | |
| { | |
| while(toupper(*s++)==toupper(*buf)) | |
| { | |
| if (*buf++=='\0') return EXACT; | |
| } | |
| } | |
| } | |
| /* At this location buf points to the first character where it no longer | |
| matches with s. So if only blanks are following, we have a partial | |
| match otherwise there is no match */ | |
| SKIP_SPACE(buf); | |
| if (*buf) | |
| return NOMATCH; | |
| /* If it happens that the reference buffer is at its end, the partial | |
| match is actually an exact match. */ | |
| return ((s[-1]=='\0') ? EXACT : PARTIAL); | |
| } | |
| /*--------------------------------------------------------------------------- | |
| | Facility : libnform | |
| | Function : static bool Check_Enum_Field( | |
| | FIELD * field, | |
| | const void * argp) | |
| | | |
| | Description : Validate buffer content to be a valid enumeration value | |
| | | |
| | Return Values : TRUE - field is valid | |
| | FALSE - field is invalid | |
| +--------------------------------------------------------------------------*/ | |
| static bool Check_Enum_Field(FIELD * field, const void * argp) | |
| { | |
| char **kwds = ((const enumARG *)argp)->kwds; | |
| bool ccase = ((const enumARG *)argp)->checkcase; | |
| bool unique = ((const enumARG *)argp)->checkunique; | |
| unsigned char *bp = (unsigned char *)field_buffer(field,0); | |
| char *s, *t, *p; | |
| int res; | |
| while( kwds && (s=(*kwds++)) ) | |
| { | |
| if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH) | |
| { | |
| p=t=s; /* t is at least a partial match */ | |
| if ((unique && res!=EXACT)) | |
| { | |
| while( kwds && (p = *kwds++) ) | |
| { | |
| if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH) | |
| { | |
| if (res==EXACT) | |
| { | |
| t = p; | |
| break; | |
| } | |
| else | |
| t = (char *)0; | |
| } | |
| } | |
| } | |
| if (t) | |
| { | |
| set_field_buffer(field,0,t); | |
| return TRUE; | |
| } | |
| if (!p) | |
| break; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| static const char *dummy[] = { (char *)0 }; | |
| /*--------------------------------------------------------------------------- | |
| | Facility : libnform | |
| | Function : static bool Next_Enum(FIELD * field, | |
| | const void * argp) | |
| | | |
| | Description : Check for the next enumeration value | |
| | | |
| | Return Values : TRUE - next value found and loaded | |
| | FALSE - no next value loaded | |
| +--------------------------------------------------------------------------*/ | |
| static bool Next_Enum(FIELD * field, const void * argp) | |
| { | |
| const enumARG *args = (const enumARG *)argp; | |
| char **kwds = args->kwds; | |
| bool ccase = args->checkcase; | |
| int cnt = args->count; | |
| unsigned char *bp = (unsigned char *)field_buffer(field,0); | |
| if (kwds) { | |
| while(cnt--) | |
| { | |
| if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT) | |
| break; | |
| } | |
| if (cnt<=0) | |
| kwds = args->kwds; | |
| if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT)) | |
| { | |
| set_field_buffer(field,0,*kwds); | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /*--------------------------------------------------------------------------- | |
| | Facility : libnform | |
| | Function : static bool Previous_Enum( | |
| | FIELD * field, | |
| | const void * argp) | |
| | | |
| | Description : Check for the previous enumeration value | |
| | | |
| | Return Values : TRUE - previous value found and loaded | |
| | FALSE - no previous value loaded | |
| +--------------------------------------------------------------------------*/ | |
| static bool Previous_Enum(FIELD * field, const void * argp) | |
| { | |
| const enumARG *args = (const enumARG *)argp; | |
| int cnt = args->count; | |
| char **kwds = &args->kwds[cnt-1]; | |
| bool ccase = args->checkcase; | |
| unsigned char *bp = (unsigned char *)field_buffer(field,0); | |
| if (kwds) { | |
| while(cnt--) | |
| { | |
| if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT) | |
| break; | |
| } | |
| if (cnt<=0) | |
| kwds = &args->kwds[args->count-1]; | |
| if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT)) | |
| { | |
| set_field_buffer(field,0,*kwds); | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| static FIELDTYPE typeENUM = { | |
| _HAS_ARGS | _HAS_CHOICE | _RESIDENT, | |
| 1, /* this is mutable, so we can't be const */ | |
| (FIELDTYPE *)0, | |
| (FIELDTYPE *)0, | |
| Make_Enum_Type, | |
| Copy_Enum_Type, | |
| Free_Enum_Type, | |
| Check_Enum_Field, | |
| NULL, | |
| Next_Enum, | |
| Previous_Enum | |
| }; | |
| FIELDTYPE* TYPE_ENUM = &typeENUM; | |
| /* fty_enum.c ends here */ |