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