1 /****************************************************************************
2 * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
3 * *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
11 * *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
14 * *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 * *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
26 * authorization. *
27 ****************************************************************************/
28
29 /***************************************************************************
30 * *
31 * Author : Juergen Pfeifer *
32 * *
33 ***************************************************************************/
34
35 #include "form.priv.h"
36
37 MODULE_ID("$Id: fty_enum.c,v 1.26 2010/05/01 21:11:07 tom Exp $")
38
39 typedef struct
40 {
41 char **kwds;
42 int count;
43 bool checkcase;
44 bool checkunique;
45 }
46 enumARG;
47
48 typedef struct
49 {
50 char **kwds;
51 int ccase;
52 int cunique;
53 }
54 enumParams;
55
56 /*---------------------------------------------------------------------------
57 | Facility : libnform
58 | Function : static void *Generic_Enum_Type(void * arg)
59 |
60 | Description : Allocate structure for enumeration type argument.
61 |
62 | Return Values : Pointer to argument structure or NULL on error
63 +--------------------------------------------------------------------------*/
64 static void *
Generic_Enum_Type(void * arg)65 Generic_Enum_Type(void *arg)
66 {
67 enumARG *argp = (enumARG *)0;
68 enumParams *params = (enumParams *) arg;
69
70 if (params)
71 {
72 argp = typeMalloc(enumARG, 1);
73
74 if (argp)
75 {
76 int cnt = 0;
77 char **kp = (char **)0;
78 char **kwds = (char **)0;
79 char **kptarget;
80 int ccase, cunique;
81
82 T((T_CREATE("enumARG %p"), (void *)argp));
83 kwds = params->kwds;
84 ccase = params->ccase;
85 cunique = params->cunique;
86
87 argp->checkcase = ccase ? TRUE : FALSE;
88 argp->checkunique = cunique ? TRUE : FALSE;
89 argp->kwds = (char **)0;
90
91 kp = kwds;
92 while (kp && (*kp++))
93 cnt++;
94 argp->count = cnt;
95
96 if (cnt > 0)
97 {
98 /* We copy the keywords, because we can't rely on the fact
99 that the caller doesn't relocate or free the memory used
100 for the keywords (maybe he has GC)
101 */
102 argp->kwds = typeMalloc(char *, cnt + 1);
103
104 kp = kwds;
105 if ((kptarget = argp->kwds) != 0)
106 {
107 while (kp && (*kp))
108 {
109 (*kptarget++) = strdup(*kp++);
110 }
111 *kptarget = (char *)0;
112 }
113 }
114 }
115 }
116 return (void *)argp;
117 }
118
119 /*---------------------------------------------------------------------------
120 | Facility : libnform
121 | Function : static void *Make_Enum_Type( va_list * ap )
122 |
123 | Description : Allocate structure for enumeration type argument.
124 |
125 | Return Values : Pointer to argument structure or NULL on error
126 +--------------------------------------------------------------------------*/
127 static void *
Make_Enum_Type(va_list * ap)128 Make_Enum_Type(va_list *ap)
129 {
130 enumParams params;
131
132 params.kwds = va_arg(*ap, char **);
133 params.ccase = va_arg(*ap, int);
134 params.cunique = va_arg(*ap, int);
135
136 return Generic_Enum_Type((void *)¶ms);
137 }
138
139 /*---------------------------------------------------------------------------
140 | Facility : libnform
141 | Function : static void *Copy_Enum_Type( const void * argp )
142 |
143 | Description : Copy structure for enumeration type argument.
144 |
145 | Return Values : Pointer to argument structure or NULL on error.
146 +--------------------------------------------------------------------------*/
147 static void *
Copy_Enum_Type(const void * argp)148 Copy_Enum_Type(const void *argp)
149 {
150 enumARG *result = (enumARG *)0;
151
152 if (argp)
153 {
154 const enumARG *ap = (const enumARG *)argp;
155
156 result = typeMalloc(enumARG, 1);
157
158 if (result)
159 {
160 T((T_CREATE("enumARG %p"), (void *)result));
161 *result = *ap;
162
163 if (ap->count > 0)
164 {
165 char **kptarget;
166 char **kp = ap->kwds;
167 result->kwds = typeMalloc(char *, 1 + ap->count);
168
169 if ((kptarget = result->kwds) != 0)
170 {
171 while (kp && (*kp))
172 {
173 (*kptarget++) = strdup(*kp++);
174 }
175 *kptarget = (char *)0;
176 }
177 }
178 }
179 }
180 return (void *)result;
181 }
182
183 /*---------------------------------------------------------------------------
184 | Facility : libnform
185 | Function : static void Free_Enum_Type( void * argp )
186 |
187 | Description : Free structure for enumeration type argument.
188 |
189 | Return Values : -
190 +--------------------------------------------------------------------------*/
191 static void
Free_Enum_Type(void * argp)192 Free_Enum_Type(void *argp)
193 {
194 if (argp)
195 {
196 const enumARG *ap = (const enumARG *)argp;
197
198 if (ap->kwds && ap->count > 0)
199 {
200 char **kp = ap->kwds;
201 int cnt = 0;
202
203 while (kp && (*kp))
204 {
205 free(*kp++);
206 cnt++;
207 }
208 assert(cnt == ap->count);
209 free(ap->kwds);
210 }
211 free(argp);
212 }
213 }
214
215 #define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++
216 #define NOMATCH 0
217 #define PARTIAL 1
218 #define EXACT 2
219
220 /*---------------------------------------------------------------------------
221 | Facility : libnform
222 | Function : static int Compare(const unsigned char * s,
223 | const unsigned char * buf,
224 | bool ccase )
225 |
226 | Description : Check whether or not the text in 'buf' matches the
227 | text in 's', at least partial.
228 |
229 | Return Values : NOMATCH - buffer doesn't match
230 | PARTIAL - buffer matches partially
231 | EXACT - buffer matches exactly
232 +--------------------------------------------------------------------------*/
233 static int
Compare(const unsigned char * s,const unsigned char * buf,bool ccase)234 Compare(const unsigned char *s, const unsigned char *buf,
235 bool ccase)
236 {
237 SKIP_SPACE(buf); /* Skip leading spaces in both texts */
238 SKIP_SPACE(s);
239
240 if (*buf == '\0')
241 {
242 return (((*s) != '\0') ? NOMATCH : EXACT);
243 }
244 else
245 {
246 if (ccase)
247 {
248 while (*s++ == *buf)
249 {
250 if (*buf++ == '\0')
251 return EXACT;
252 }
253 }
254 else
255 {
256 while (toupper(*s++) == toupper(*buf))
257 {
258 if (*buf++ == '\0')
259 return EXACT;
260 }
261 }
262 }
263 /* At this location buf points to the first character where it no longer
264 matches with s. So if only blanks are following, we have a partial
265 match otherwise there is no match */
266 SKIP_SPACE(buf);
267 if (*buf)
268 return NOMATCH;
269
270 /* If it happens that the reference buffer is at its end, the partial
271 match is actually an exact match. */
272 return ((s[-1] != '\0') ? PARTIAL : EXACT);
273 }
274
275 /*---------------------------------------------------------------------------
276 | Facility : libnform
277 | Function : static bool Check_Enum_Field(
278 | FIELD * field,
279 | const void * argp)
280 |
281 | Description : Validate buffer content to be a valid enumeration value
282 |
283 | Return Values : TRUE - field is valid
284 | FALSE - field is invalid
285 +--------------------------------------------------------------------------*/
286 static bool
Check_Enum_Field(FIELD * field,const void * argp)287 Check_Enum_Field(FIELD *field, const void *argp)
288 {
289 char **kwds = ((const enumARG *)argp)->kwds;
290 bool ccase = ((const enumARG *)argp)->checkcase;
291 bool unique = ((const enumARG *)argp)->checkunique;
292 unsigned char *bp = (unsigned char *)field_buffer(field, 0);
293 char *s, *t, *p;
294 int res;
295
296 while (kwds && (s = (*kwds++)))
297 {
298 if ((res = Compare((unsigned char *)s, bp, ccase)) != NOMATCH)
299 {
300 p = t = s; /* t is at least a partial match */
301 if ((unique && res != EXACT))
302 {
303 while (kwds && (p = *kwds++))
304 {
305 if ((res = Compare((unsigned char *)p, bp, ccase)) != NOMATCH)
306 {
307 if (res == EXACT)
308 {
309 t = p;
310 break;
311 }
312 else
313 t = (char *)0;
314 }
315 }
316 }
317 if (t)
318 {
319 set_field_buffer(field, 0, t);
320 return TRUE;
321 }
322 if (!p)
323 break;
324 }
325 }
326 return FALSE;
327 }
328
329 static const char *dummy[] =
330 {(char *)0};
331
332 /*---------------------------------------------------------------------------
333 | Facility : libnform
334 | Function : static bool Next_Enum(FIELD * field,
335 | const void * argp)
336 |
337 | Description : Check for the next enumeration value
338 |
339 | Return Values : TRUE - next value found and loaded
340 | FALSE - no next value loaded
341 +--------------------------------------------------------------------------*/
342 static bool
Next_Enum(FIELD * field,const void * argp)343 Next_Enum(FIELD *field, const void *argp)
344 {
345 const enumARG *args = (const enumARG *)argp;
346 char **kwds = args->kwds;
347 bool ccase = args->checkcase;
348 int cnt = args->count;
349 unsigned char *bp = (unsigned char *)field_buffer(field, 0);
350
351 if (kwds)
352 {
353 while (cnt--)
354 {
355 if (Compare((unsigned char *)(*kwds++), bp, ccase) == EXACT)
356 break;
357 }
358 if (cnt <= 0)
359 kwds = args->kwds;
360 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT))
361 {
362 set_field_buffer(field, 0, *kwds);
363 return TRUE;
364 }
365 }
366 return FALSE;
367 }
368
369 /*---------------------------------------------------------------------------
370 | Facility : libnform
371 | Function : static bool Previous_Enum(
372 | FIELD * field,
373 | const void * argp)
374 |
375 | Description : Check for the previous enumeration value
376 |
377 | Return Values : TRUE - previous value found and loaded
378 | FALSE - no previous value loaded
379 +--------------------------------------------------------------------------*/
380 static bool
Previous_Enum(FIELD * field,const void * argp)381 Previous_Enum(FIELD *field, const void *argp)
382 {
383 const enumARG *args = (const enumARG *)argp;
384 int cnt = args->count;
385 char **kwds = &args->kwds[cnt - 1];
386 bool ccase = args->checkcase;
387 unsigned char *bp = (unsigned char *)field_buffer(field, 0);
388
389 if (kwds)
390 {
391 while (cnt--)
392 {
393 if (Compare((unsigned char *)(*kwds--), bp, ccase) == EXACT)
394 break;
395 }
396
397 if (cnt <= 0)
398 kwds = &args->kwds[args->count - 1];
399
400 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT))
401 {
402 set_field_buffer(field, 0, *kwds);
403 return TRUE;
404 }
405 }
406 return FALSE;
407 }
408
409 static FIELDTYPE typeENUM =
410 {
411 _HAS_ARGS | _HAS_CHOICE | _RESIDENT,
412 1, /* this is mutable, so we can't be const */
413 (FIELDTYPE *)0,
414 (FIELDTYPE *)0,
415 Make_Enum_Type,
416 Copy_Enum_Type,
417 Free_Enum_Type,
418 INIT_FT_FUNC(Check_Enum_Field),
419 INIT_FT_FUNC(NULL),
420 INIT_FT_FUNC(Next_Enum),
421 INIT_FT_FUNC(Previous_Enum),
422 #if NCURSES_INTEROP_FUNCS
423 Generic_Enum_Type
424 #endif
425 };
426
427 NCURSES_EXPORT_VAR(FIELDTYPE *)
428 TYPE_ENUM = &typeENUM;
429
430 #if NCURSES_INTEROP_FUNCS
431 /* The next routines are to simplify the use of ncurses from
432 programming languages with restictions on interop with C level
433 constructs (e.g. variable access or va_list + ellipsis constructs)
434 */
435 NCURSES_EXPORT(FIELDTYPE *)
_nc_TYPE_ENUM(void)436 _nc_TYPE_ENUM(void)
437 {
438 return TYPE_ENUM;
439 }
440 #endif
441
442 /* fty_enum.c ends here */
443