fty_enum.c revision 66963
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.13 2000/09/10 00:55:26 juergen 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
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+--------------------------------------------------------------------------*/
64static 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+--------------------------------------------------------------------------*/
87static 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+--------------------------------------------------------------------------*/
111static 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+--------------------------------------------------------------------------*/
161static 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
203static 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+--------------------------------------------------------------------------*/
215static 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+--------------------------------------------------------------------------*/
251static 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
279static 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
293FIELDTYPE* TYPE_ENUM = &typeENUM;
294
295/* fty_enum.c ends here */
296