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