ncurses 4.1
[ncurses.git] / form / fty_enum.c
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@T-Online.de                   *
11 *                                                                          *
12 ***************************************************************************/
13
14 #include "form.priv.h"
15
16 MODULE_ID("$Id: fty_enum.c,v 1.5 1997/02/15 17:33:59 tom Exp $")
17
18 typedef 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 +--------------------------------------------------------------------------*/
33 static 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 +--------------------------------------------------------------------------*/
63 static void *Copy_Enum_Type(const void * argp)
64 {
65   const enumARG *ap = (const enumARG *)argp;
66   enumARG *new = (enumARG *)0;
67
68   if (argp)
69     {
70       new = (enumARG *)malloc(sizeof(enumARG));
71       if (new)
72         *new = *ap;
73     }
74   return (void *)new;
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 +--------------------------------------------------------------------------*/
85 static 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 +--------------------------------------------------------------------------*/
109 static 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               s++;
133               if (*buf++=='\0') return EXACT;
134             }
135         }
136     }
137   /* At this location buf points to the first character where it no longer
138      matches with s. So if only blanks are following, we have a partial
139      match otherwise there is no match */
140   SKIP_SPACE(buf);
141   if (*buf) 
142     return NOMATCH;
143
144   /* If it happens that the reference buffer is at its end, the partial
145      match is actually an exact match. */
146   return ((s[-1]!='\0') ? PARTIAL : EXACT);
147 }
148
149 /*---------------------------------------------------------------------------
150 |   Facility      :  libnform  
151 |   Function      :  static bool Check_Enum_Field(
152 |                                      FIELD * field,
153 |                                      const void  * argp)
154 |   
155 |   Description   :  Validate buffer content to be a valid enumeration value
156 |
157 |   Return Values :  TRUE  - field is valid
158 |                    FALSE - field is invalid
159 +--------------------------------------------------------------------------*/
160 static bool Check_Enum_Field(FIELD * field, const void  * argp)
161 {
162   char **kwds       = ((const enumARG *)argp)->kwds;
163   bool ccase        = ((const enumARG *)argp)->checkcase;
164   bool unique       = ((const enumARG *)argp)->checkunique;
165   unsigned char *bp = (unsigned char *)field_buffer(field,0);
166   char *s, *t, *p;
167   int res;
168   
169   while( (s=(*kwds++)) )
170     {
171       if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH)
172         {
173           t=s;
174           if ((unique && res!=EXACT)) 
175             {
176               while( (p = *kwds++) )
177                 {
178                   if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH)
179                     {
180                       if (res==EXACT)
181                         {
182                           t = p;
183                           break;
184                         }       
185                       t = (char *)0;
186                     }
187                 }
188             }
189           if (t)
190             {
191               set_field_buffer(field,0,t);
192               return TRUE;
193             }
194         }
195     }
196   return FALSE;
197 }
198
199 static const char *dummy[] = { (char *)0 };
200
201 /*---------------------------------------------------------------------------
202 |   Facility      :  libnform  
203 |   Function      :  static bool Next_Enum(FIELD * field,
204 |                                          const void * argp)
205 |   
206 |   Description   :  Check for the next enumeration value
207 |
208 |   Return Values :  TRUE  - next value found and loaded
209 |                    FALSE - no next value loaded
210 +--------------------------------------------------------------------------*/
211 static bool Next_Enum(FIELD * field, const void * argp)
212 {
213   const enumARG *args = (const enumARG *)argp;
214   char **kwds       = args->kwds;
215   bool ccase        = args->checkcase;
216   int cnt           = args->count;
217   unsigned char *bp = (unsigned char *)field_buffer(field,0);
218
219   while(cnt--)
220     {
221       if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT) 
222         break;
223     }
224   if (cnt<=0)
225     kwds = args->kwds;
226   if ((cnt>=0) || (Compare((unsigned char *)dummy,bp,ccase)==EXACT))
227     {
228       set_field_buffer(field,0,*kwds);
229       return TRUE;
230     }
231   return FALSE;
232 }
233
234 /*---------------------------------------------------------------------------
235 |   Facility      :  libnform  
236 |   Function      :  static bool Previous_Enum(
237 |                                          FIELD * field,
238 |                                          const void * argp)
239 |   
240 |   Description   :  Check for the previous enumeration value
241 |
242 |   Return Values :  TRUE  - previous value found and loaded
243 |                    FALSE - no previous value loaded
244 +--------------------------------------------------------------------------*/
245 static bool Previous_Enum(FIELD * field, const void * argp)
246 {
247   const enumARG *args = (const enumARG *)argp;
248   int cnt       = args->count;
249   char **kwds   = &args->kwds[cnt-1];
250   bool ccase    = args->checkcase;
251   unsigned char *bp = (unsigned char *)field_buffer(field,0);
252
253   while(cnt--)
254     {
255       if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT) 
256         break;
257     }
258
259   if (cnt<=0)
260     kwds  = &args->kwds[args->count-1];
261
262   if ((cnt>=0) || (Compare((unsigned char *)dummy,bp,ccase)==EXACT))
263     {
264       set_field_buffer(field,0,*kwds);
265       return TRUE;
266     }
267   return FALSE;
268 }
269
270
271 static FIELDTYPE typeENUM = {
272   _HAS_ARGS | _HAS_CHOICE | _RESIDENT,
273   1,                           /* this is mutable, so we can't be const */
274   (FIELDTYPE *)0,
275   (FIELDTYPE *)0,
276   Make_Enum_Type,
277   Copy_Enum_Type,
278   Free_Enum_Type,
279   Check_Enum_Field,
280   NULL,
281   Next_Enum,
282   Previous_Enum
283 };
284
285 FIELDTYPE* TYPE_ENUM = &typeENUM;
286
287 /* fty_enum.c ends here */