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