blob: d3351644ef1849f2aa9de6dfd7ab31674cc08e8c [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
Steve Kondikae271bc2015-11-15 02:50:53 +01002 * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303 * *
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
Steve Kondikae271bc2015-11-15 02:50:53 +010037MODULE_ID("$Id: fty_enum.c,v 1.26 2010/05/01 21:11:07 tom Exp $")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053038
39typedef struct
40 {
41 char **kwds;
42 int count;
43 bool checkcase;
44 bool checkunique;
45 }
46enumARG;
47
Steve Kondikae271bc2015-11-15 02:50:53 +010048typedef struct
49 {
50 char **kwds;
51 int ccase;
52 int cunique;
53 }
54enumParams;
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+--------------------------------------------------------------------------*/
64static void *
65Generic_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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530119/*---------------------------------------------------------------------------
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+--------------------------------------------------------------------------*/
127static void *
128Make_Enum_Type(va_list *ap)
129{
Steve Kondikae271bc2015-11-15 02:50:53 +0100130 enumParams params;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530131
Steve Kondikae271bc2015-11-15 02:50:53 +0100132 params.kwds = va_arg(*ap, char **);
133 params.ccase = va_arg(*ap, int);
134 params.cunique = va_arg(*ap, int);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530135
Steve Kondikae271bc2015-11-15 02:50:53 +0100136 return Generic_Enum_Type((void *)&params);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530137}
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+--------------------------------------------------------------------------*/
147static void *
148Copy_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 {
Steve Kondikae271bc2015-11-15 02:50:53 +0100160 T((T_CREATE("enumARG %p"), (void *)result));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530161 *result = *ap;
Steve Kondikae271bc2015-11-15 02:50:53 +0100162
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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530178 }
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+--------------------------------------------------------------------------*/
191static void
192Free_Enum_Type(void *argp)
193{
194 if (argp)
Steve Kondikae271bc2015-11-15 02:50:53 +0100195 {
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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530213}
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+--------------------------------------------------------------------------*/
233static int
234Compare(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+--------------------------------------------------------------------------*/
286static bool
287Check_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
329static 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+--------------------------------------------------------------------------*/
342static bool
343Next_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+--------------------------------------------------------------------------*/
380static bool
381Previous_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
409static 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,
Steve Kondikae271bc2015-11-15 02:50:53 +0100418 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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530425};
426
427NCURSES_EXPORT_VAR(FIELDTYPE *)
428TYPE_ENUM = &typeENUM;
429
Steve Kondikae271bc2015-11-15 02:50:53 +0100430#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*/
435NCURSES_EXPORT(FIELDTYPE *)
436_nc_TYPE_ENUM(void)
437{
438 return TYPE_ENUM;
439}
440#endif
441
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530442/* fty_enum.c ends here */