1/*2* THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.3* You may freely copy it for use as a template for your own field types.4* If you develop a field type that might be of general use, please send5* it back to the ncurses maintainers for inclusion in the next version.6*/7/***************************************************************************8* *9* Author : Juergen Pfeifer, [email protected] *10* *11***************************************************************************/1213#include "form.priv.h"1415MODULE_ID("$Id$")1617typedef struct {18char **kwds;19int count;20bool checkcase;21bool checkunique;22} enumARG;2324/*---------------------------------------------------------------------------25| Facility : libnform26| Function : static void *Make_Enum_Type( va_list * ap )27|28| Description : Allocate structure for enumeration type argument.29|30| Return Values : Pointer to argument structure or NULL on error31+--------------------------------------------------------------------------*/32static void *Make_Enum_Type(va_list * ap)33{34enumARG *argp = (enumARG *)malloc(sizeof(enumARG));3536if (argp)37{38int cnt = 0;39char **kp = (char **)0;40int ccase, cunique;4142argp->kwds = va_arg(*ap,char **);43ccase = va_arg(*ap,int);44cunique = va_arg(*ap,int);45argp->checkcase = ccase ? TRUE : FALSE;46argp->checkunique = cunique ? TRUE : FALSE;4748kp = argp->kwds;49while( kp && (*kp++) ) cnt++;50argp->count = cnt;51}52return (void *)argp;53}5455/*---------------------------------------------------------------------------56| Facility : libnform57| 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{65enumARG *result = (enumARG *)0;6667if (argp)68{69const enumARG *ap = (const enumARG *)argp;7071result = (enumARG *)malloc(sizeof(enumARG));72if (result)73*result = *ap;74}75return (void *)result;76}7778/*---------------------------------------------------------------------------79| Facility : libnform80| Function : static void Free_Enum_Type( void * argp )81|82| Description : Free structure for enumeration type argument.83|84| Return Values : -85+--------------------------------------------------------------------------*/86static void Free_Enum_Type(void * argp)87{88if (argp)89free(argp);90}9192#define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++93#define NOMATCH 094#define PARTIAL 195#define EXACT 29697/*---------------------------------------------------------------------------98| Facility : libnform99| Function : static int Compare(const unsigned char * s,100| const unsigned char * buf,101| bool ccase )102|103| Description : Check whether or not the text in 'buf' matches the104| text in 's', at least partial.105|106| Return Values : NOMATCH - buffer doesn't match107| PARTIAL - buffer matches partially108| EXACT - buffer matches exactly109+--------------------------------------------------------------------------*/110static int Compare(const unsigned char *s, const unsigned char *buf,111bool ccase)112{113SKIP_SPACE(buf); /* Skip leading spaces in both texts */114SKIP_SPACE(s);115116if (*buf=='\0')117{118return (((*s)=='\0') ? EXACT : NOMATCH);119}120else121{122if (ccase)123{124while(*s++ == *buf)125{126if (*buf++=='\0') return EXACT;127}128}129else130{131while(toupper(*s++)==toupper(*buf))132{133if (*buf++=='\0') return EXACT;134}135}136}137/* At this location buf points to the first character where it no longer138matches with s. So if only blanks are following, we have a partial139match otherwise there is no match */140SKIP_SPACE(buf);141if (*buf)142return NOMATCH;143144/* If it happens that the reference buffer is at its end, the partial145match is actually an exact match. */146return ((s[-1]=='\0') ? EXACT : PARTIAL);147}148149/*---------------------------------------------------------------------------150| Facility : libnform151| Function : static bool Check_Enum_Field(152| FIELD * field,153| const void * argp)154|155| Description : Validate buffer content to be a valid enumeration value156|157| Return Values : TRUE - field is valid158| FALSE - field is invalid159+--------------------------------------------------------------------------*/160static bool Check_Enum_Field(FIELD * field, const void * argp)161{162char **kwds = ((const enumARG *)argp)->kwds;163bool ccase = ((const enumARG *)argp)->checkcase;164bool unique = ((const enumARG *)argp)->checkunique;165unsigned char *bp = (unsigned char *)field_buffer(field,0);166char *s, *t, *p;167int res;168169while( kwds && (s=(*kwds++)) )170{171if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH)172{173p=t=s; /* t is at least a partial match */174if ((unique && res!=EXACT))175{176while( kwds && (p = *kwds++) )177{178if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH)179{180if (res==EXACT)181{182t = p;183break;184}185else186t = (char *)0;187}188}189}190if (t)191{192set_field_buffer(field,0,t);193return TRUE;194}195if (!p)196break;197}198}199return FALSE;200}201202static const char *dummy[] = { (char *)0 };203204/*---------------------------------------------------------------------------205| Facility : libnform206| Function : static bool Next_Enum(FIELD * field,207| const void * argp)208|209| Description : Check for the next enumeration value210|211| Return Values : TRUE - next value found and loaded212| FALSE - no next value loaded213+--------------------------------------------------------------------------*/214static bool Next_Enum(FIELD * field, const void * argp)215{216const enumARG *args = (const enumARG *)argp;217char **kwds = args->kwds;218bool ccase = args->checkcase;219int cnt = args->count;220unsigned char *bp = (unsigned char *)field_buffer(field,0);221222if (kwds) {223while(cnt--)224{225if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT)226break;227}228if (cnt<=0)229kwds = args->kwds;230if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))231{232set_field_buffer(field,0,*kwds);233return TRUE;234}235}236return FALSE;237}238239/*---------------------------------------------------------------------------240| Facility : libnform241| Function : static bool Previous_Enum(242| FIELD * field,243| const void * argp)244|245| Description : Check for the previous enumeration value246|247| Return Values : TRUE - previous value found and loaded248| FALSE - no previous value loaded249+--------------------------------------------------------------------------*/250static bool Previous_Enum(FIELD * field, const void * argp)251{252const enumARG *args = (const enumARG *)argp;253int cnt = args->count;254char **kwds = &args->kwds[cnt-1];255bool ccase = args->checkcase;256unsigned char *bp = (unsigned char *)field_buffer(field,0);257258if (kwds) {259while(cnt--)260{261if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT)262break;263}264265if (cnt<=0)266kwds = &args->kwds[args->count-1];267268if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))269{270set_field_buffer(field,0,*kwds);271return TRUE;272}273}274return FALSE;275}276277278static FIELDTYPE typeENUM = {279_HAS_ARGS | _HAS_CHOICE | _RESIDENT,2801, /* this is mutable, so we can't be const */281(FIELDTYPE *)0,282(FIELDTYPE *)0,283Make_Enum_Type,284Copy_Enum_Type,285Free_Enum_Type,286Check_Enum_Field,287NULL,288Next_Enum,289Previous_Enum290};291292FIELDTYPE* TYPE_ENUM = &typeENUM;293294/* fty_enum.c ends here */295296297