blob: 16ffae11036fa1429353e7c92889238df0216ee1 [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
micky3879b9f5e72025-07-08 18:04:53 -04002 * Copyright 2020,2021 Thomas E. Dickey *
3 * Copyright 1998-2009,2010 Free Software Foundation, Inc. *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304 * *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
12 * *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
15 * *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * *
24 * Except as contained in this notice, the name(s) of the above copyright *
25 * holders shall not be used in advertising or otherwise to promote the *
26 * sale, use or other dealings in this Software without prior written *
27 * authorization. *
28 ****************************************************************************/
29
30/***************************************************************************
31* *
32* Author : Juergen Pfeifer *
33* *
34***************************************************************************/
35
36#include "form.priv.h"
37
micky3879b9f5e72025-07-08 18:04:53 -040038MODULE_ID("$Id: fty_enum.c,v 1.33 2021/06/17 21:11:08 tom Exp $")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053039
40typedef struct
41 {
42 char **kwds;
43 int count;
44 bool checkcase;
45 bool checkunique;
46 }
47enumARG;
48
Steve Kondikae271bc2015-11-15 02:50:53 +010049typedef struct
50 {
51 char **kwds;
52 int ccase;
53 int cunique;
54 }
55enumParams;
56
57/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -040058| Facility : libnform
Steve Kondikae271bc2015-11-15 02:50:53 +010059| Function : static void *Generic_Enum_Type(void * arg)
micky3879b9f5e72025-07-08 18:04:53 -040060|
Steve Kondikae271bc2015-11-15 02:50:53 +010061| Description : Allocate structure for enumeration type argument.
62|
63| Return Values : Pointer to argument structure or NULL on error
64+--------------------------------------------------------------------------*/
65static void *
66Generic_Enum_Type(void *arg)
67{
68 enumARG *argp = (enumARG *)0;
micky3879b9f5e72025-07-08 18:04:53 -040069 enumParams *params = (enumParams *)arg;
Steve Kondikae271bc2015-11-15 02:50:53 +010070
71 if (params)
72 {
73 argp = typeMalloc(enumARG, 1);
74
75 if (argp)
76 {
77 int cnt = 0;
78 char **kp = (char **)0;
79 char **kwds = (char **)0;
Steve Kondikae271bc2015-11-15 02:50:53 +010080 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 {
micky3879b9f5e72025-07-08 18:04:53 -040098 char **kptarget;
99
Steve Kondikae271bc2015-11-15 02:50:53 +0100100 /* We copy the keywords, because we can't rely on the fact
101 that the caller doesn't relocate or free the memory used
102 for the keywords (maybe he has GC)
103 */
104 argp->kwds = typeMalloc(char *, cnt + 1);
105
106 kp = kwds;
107 if ((kptarget = argp->kwds) != 0)
108 {
109 while (kp && (*kp))
110 {
111 (*kptarget++) = strdup(*kp++);
112 }
113 *kptarget = (char *)0;
114 }
115 }
116 }
117 }
118 return (void *)argp;
119}
120
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530121/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400122| Facility : libnform
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530123| Function : static void *Make_Enum_Type( va_list * ap )
micky3879b9f5e72025-07-08 18:04:53 -0400124|
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530125| Description : Allocate structure for enumeration type argument.
126|
127| Return Values : Pointer to argument structure or NULL on error
128+--------------------------------------------------------------------------*/
129static void *
130Make_Enum_Type(va_list *ap)
131{
Steve Kondikae271bc2015-11-15 02:50:53 +0100132 enumParams params;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530133
Steve Kondikae271bc2015-11-15 02:50:53 +0100134 params.kwds = va_arg(*ap, char **);
135 params.ccase = va_arg(*ap, int);
136 params.cunique = va_arg(*ap, int);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530137
Steve Kondikae271bc2015-11-15 02:50:53 +0100138 return Generic_Enum_Type((void *)&params);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530139}
140
141/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400142| Facility : libnform
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530143| Function : static void *Copy_Enum_Type( const void * argp )
micky3879b9f5e72025-07-08 18:04:53 -0400144|
145| Description : Copy structure for enumeration type argument.
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530146|
147| Return Values : Pointer to argument structure or NULL on error.
148+--------------------------------------------------------------------------*/
149static void *
150Copy_Enum_Type(const void *argp)
151{
152 enumARG *result = (enumARG *)0;
153
154 if (argp)
155 {
156 const enumARG *ap = (const enumARG *)argp;
157
158 result = typeMalloc(enumARG, 1);
159
160 if (result)
161 {
Steve Kondikae271bc2015-11-15 02:50:53 +0100162 T((T_CREATE("enumARG %p"), (void *)result));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530163 *result = *ap;
Steve Kondikae271bc2015-11-15 02:50:53 +0100164
165 if (ap->count > 0)
166 {
167 char **kptarget;
168 char **kp = ap->kwds;
169 result->kwds = typeMalloc(char *, 1 + ap->count);
170
171 if ((kptarget = result->kwds) != 0)
172 {
173 while (kp && (*kp))
174 {
175 (*kptarget++) = strdup(*kp++);
176 }
177 *kptarget = (char *)0;
178 }
179 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530180 }
181 }
182 return (void *)result;
183}
184
185/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400186| Facility : libnform
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530187| Function : static void Free_Enum_Type( void * argp )
micky3879b9f5e72025-07-08 18:04:53 -0400188|
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530189| Description : Free structure for enumeration type argument.
190|
191| Return Values : -
192+--------------------------------------------------------------------------*/
193static void
194Free_Enum_Type(void *argp)
195{
196 if (argp)
Steve Kondikae271bc2015-11-15 02:50:53 +0100197 {
198 const enumARG *ap = (const enumARG *)argp;
199
200 if (ap->kwds && ap->count > 0)
201 {
202 char **kp = ap->kwds;
203 int cnt = 0;
204
205 while (kp && (*kp))
206 {
207 free(*kp++);
208 cnt++;
209 }
210 assert(cnt == ap->count);
211 free(ap->kwds);
212 }
213 free(argp);
214 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530215}
216
217#define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++
218#define NOMATCH 0
219#define PARTIAL 1
220#define EXACT 2
221
222/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400223| Facility : libnform
224| Function : static int Compare(const unsigned char * s,
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530225| const unsigned char * buf,
226| bool ccase )
micky3879b9f5e72025-07-08 18:04:53 -0400227|
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530228| Description : Check whether or not the text in 'buf' matches the
229| text in 's', at least partial.
230|
231| Return Values : NOMATCH - buffer doesn't match
232| PARTIAL - buffer matches partially
233| EXACT - buffer matches exactly
234+--------------------------------------------------------------------------*/
235static int
236Compare(const unsigned char *s, const unsigned char *buf,
237 bool ccase)
238{
239 SKIP_SPACE(buf); /* Skip leading spaces in both texts */
240 SKIP_SPACE(s);
241
242 if (*buf == '\0')
243 {
244 return (((*s) != '\0') ? NOMATCH : EXACT);
245 }
246 else
247 {
248 if (ccase)
249 {
250 while (*s++ == *buf)
251 {
252 if (*buf++ == '\0')
253 return EXACT;
254 }
255 }
256 else
257 {
258 while (toupper(*s++) == toupper(*buf))
259 {
260 if (*buf++ == '\0')
261 return EXACT;
262 }
263 }
264 }
265 /* At this location buf points to the first character where it no longer
266 matches with s. So if only blanks are following, we have a partial
267 match otherwise there is no match */
268 SKIP_SPACE(buf);
269 if (*buf)
270 return NOMATCH;
271
272 /* If it happens that the reference buffer is at its end, the partial
273 match is actually an exact match. */
274 return ((s[-1] != '\0') ? PARTIAL : EXACT);
275}
276
277/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400278| Facility : libnform
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530279| Function : static bool Check_Enum_Field(
280| FIELD * field,
281| const void * argp)
micky3879b9f5e72025-07-08 18:04:53 -0400282|
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530283| Description : Validate buffer content to be a valid enumeration value
284|
285| Return Values : TRUE - field is valid
286| FALSE - field is invalid
287+--------------------------------------------------------------------------*/
288static bool
289Check_Enum_Field(FIELD *field, const void *argp)
290{
291 char **kwds = ((const enumARG *)argp)->kwds;
292 bool ccase = ((const enumARG *)argp)->checkcase;
293 bool unique = ((const enumARG *)argp)->checkunique;
294 unsigned char *bp = (unsigned char *)field_buffer(field, 0);
295 char *s, *t, *p;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530296
297 while (kwds && (s = (*kwds++)))
298 {
micky3879b9f5e72025-07-08 18:04:53 -0400299 int res;
300
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530301 if ((res = Compare((unsigned char *)s, bp, ccase)) != NOMATCH)
302 {
303 p = t = s; /* t is at least a partial match */
304 if ((unique && res != EXACT))
305 {
306 while (kwds && (p = *kwds++))
307 {
308 if ((res = Compare((unsigned char *)p, bp, ccase)) != NOMATCH)
309 {
310 if (res == EXACT)
311 {
312 t = p;
313 break;
314 }
315 else
316 t = (char *)0;
317 }
318 }
319 }
320 if (t)
321 {
322 set_field_buffer(field, 0, t);
323 return TRUE;
324 }
325 if (!p)
326 break;
327 }
328 }
329 return FALSE;
330}
331
332static const char *dummy[] =
333{(char *)0};
334
335/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400336| Facility : libnform
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530337| Function : static bool Next_Enum(FIELD * field,
338| const void * argp)
micky3879b9f5e72025-07-08 18:04:53 -0400339|
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530340| Description : Check for the next enumeration value
341|
342| Return Values : TRUE - next value found and loaded
343| FALSE - no next value loaded
344+--------------------------------------------------------------------------*/
345static bool
346Next_Enum(FIELD *field, const void *argp)
347{
348 const enumARG *args = (const enumARG *)argp;
349 char **kwds = args->kwds;
350 bool ccase = args->checkcase;
351 int cnt = args->count;
352 unsigned char *bp = (unsigned char *)field_buffer(field, 0);
353
354 if (kwds)
355 {
356 while (cnt--)
357 {
358 if (Compare((unsigned char *)(*kwds++), bp, ccase) == EXACT)
359 break;
360 }
361 if (cnt <= 0)
362 kwds = args->kwds;
363 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT))
364 {
365 set_field_buffer(field, 0, *kwds);
366 return TRUE;
367 }
368 }
369 return FALSE;
370}
371
372/*---------------------------------------------------------------------------
micky3879b9f5e72025-07-08 18:04:53 -0400373| Facility : libnform
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530374| Function : static bool Previous_Enum(
375| FIELD * field,
376| const void * argp)
micky3879b9f5e72025-07-08 18:04:53 -0400377|
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530378| Description : Check for the previous enumeration value
379|
380| Return Values : TRUE - previous value found and loaded
381| FALSE - no previous value loaded
382+--------------------------------------------------------------------------*/
383static bool
384Previous_Enum(FIELD *field, const void *argp)
385{
386 const enumARG *args = (const enumARG *)argp;
387 int cnt = args->count;
388 char **kwds = &args->kwds[cnt - 1];
389 bool ccase = args->checkcase;
390 unsigned char *bp = (unsigned char *)field_buffer(field, 0);
391
392 if (kwds)
393 {
394 while (cnt--)
395 {
396 if (Compare((unsigned char *)(*kwds--), bp, ccase) == EXACT)
397 break;
398 }
399
400 if (cnt <= 0)
401 kwds = &args->kwds[args->count - 1];
402
403 if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT))
404 {
405 set_field_buffer(field, 0, *kwds);
406 return TRUE;
407 }
408 }
409 return FALSE;
410}
411
412static FIELDTYPE typeENUM =
413{
414 _HAS_ARGS | _HAS_CHOICE | _RESIDENT,
415 1, /* this is mutable, so we can't be const */
416 (FIELDTYPE *)0,
417 (FIELDTYPE *)0,
418 Make_Enum_Type,
419 Copy_Enum_Type,
420 Free_Enum_Type,
Steve Kondikae271bc2015-11-15 02:50:53 +0100421 INIT_FT_FUNC(Check_Enum_Field),
422 INIT_FT_FUNC(NULL),
423 INIT_FT_FUNC(Next_Enum),
424 INIT_FT_FUNC(Previous_Enum),
425#if NCURSES_INTEROP_FUNCS
426 Generic_Enum_Type
427#endif
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530428};
429
micky3879b9f5e72025-07-08 18:04:53 -0400430FORM_EXPORT_VAR(FIELDTYPE *) TYPE_ENUM = &typeENUM;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530431
Steve Kondikae271bc2015-11-15 02:50:53 +0100432#if NCURSES_INTEROP_FUNCS
433/* The next routines are to simplify the use of ncurses from
micky3879b9f5e72025-07-08 18:04:53 -0400434 programming languages with restrictions on interop with C level
Steve Kondikae271bc2015-11-15 02:50:53 +0100435 constructs (e.g. variable access or va_list + ellipsis constructs)
436*/
micky3879b9f5e72025-07-08 18:04:53 -0400437FORM_EXPORT(FIELDTYPE *)
Steve Kondikae271bc2015-11-15 02:50:53 +0100438_nc_TYPE_ENUM(void)
439{
440 return TYPE_ENUM;
441}
442#endif
443
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530444/* fty_enum.c ends here */