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