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