xref: /freebsd/contrib/ncurses/form/fty_enum.c (revision b85e1f7d05ac7889868f2364474e02b6a024af25)
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 *
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 *
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
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
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
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
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
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