1166124Srafan/****************************************************************************
2174993Srafan * Copyright (c) 1998-2006,2007 Free Software Foundation, Inc.              *
3166124Srafan *                                                                          *
4166124Srafan * Permission is hereby granted, free of charge, to any person obtaining a  *
5166124Srafan * copy of this software and associated documentation files (the            *
6166124Srafan * "Software"), to deal in the Software without restriction, including      *
7166124Srafan * without limitation the rights to use, copy, modify, merge, publish,      *
8166124Srafan * distribute, distribute with modifications, sublicense, and/or sell       *
9166124Srafan * copies of the Software, and to permit persons to whom the Software is    *
10166124Srafan * furnished to do so, subject to the following conditions:                 *
11166124Srafan *                                                                          *
12166124Srafan * The above copyright notice and this permission notice shall be included  *
13166124Srafan * in all copies or substantial portions of the Software.                   *
14166124Srafan *                                                                          *
15166124Srafan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16166124Srafan * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17166124Srafan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18166124Srafan * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19166124Srafan * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20166124Srafan * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21166124Srafan * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22166124Srafan *                                                                          *
23166124Srafan * Except as contained in this notice, the name(s) of the above copyright   *
24166124Srafan * holders shall not be used in advertising or otherwise to promote the     *
25166124Srafan * sale, use or other dealings in this Software without prior written       *
26166124Srafan * authorization.                                                           *
27166124Srafan ****************************************************************************/
2850276Speter
2950276Speter/***************************************************************************
3050276Speter*                                                                          *
31166124Srafan*  Author : Juergen Pfeifer                                                *
3250276Speter*                                                                          *
3350276Speter***************************************************************************/
3450276Speter
3550276Speter#include "form.priv.h"
3650276Speter
37174993SrafanMODULE_ID("$Id: fty_enum.c,v 1.22 2007/10/13 19:32:26 tom Exp $")
3850276Speter
39166124Srafantypedef struct
40166124Srafan  {
41166124Srafan    char **kwds;
42166124Srafan    int count;
43166124Srafan    bool checkcase;
44166124Srafan    bool checkunique;
45166124Srafan  }
46166124SrafanenumARG;
4750276Speter
4850276Speter/*---------------------------------------------------------------------------
4950276Speter|   Facility      :  libnform
5050276Speter|   Function      :  static void *Make_Enum_Type( va_list * ap )
5150276Speter|
5250276Speter|   Description   :  Allocate structure for enumeration type argument.
5350276Speter|
5450276Speter|   Return Values :  Pointer to argument structure or NULL on error
5550276Speter+--------------------------------------------------------------------------*/
56166124Srafanstatic void *
57166124SrafanMake_Enum_Type(va_list *ap)
5850276Speter{
59174993Srafan  enumARG *argp = typeMalloc(enumARG, 1);
6050276Speter
6150276Speter  if (argp)
6250276Speter    {
6366963Speter      int cnt = 0;
6466963Speter      char **kp = (char **)0;
6550276Speter      int ccase, cunique;
6666963Speter
67174993Srafan      T((T_CREATE("enumARG %p"), argp));
68166124Srafan      argp->kwds = va_arg(*ap, char **);
69166124Srafan      ccase = va_arg(*ap, int);
70166124Srafan      cunique = va_arg(*ap, int);
71166124Srafan
72166124Srafan      argp->checkcase = ccase ? TRUE : FALSE;
7350276Speter      argp->checkunique = cunique ? TRUE : FALSE;
7466963Speter
7550276Speter      kp = argp->kwds;
76166124Srafan      while (kp && (*kp++))
77166124Srafan	cnt++;
7850276Speter      argp->count = cnt;
7950276Speter    }
8050276Speter  return (void *)argp;
8150276Speter}
8250276Speter
8350276Speter/*---------------------------------------------------------------------------
8450276Speter|   Facility      :  libnform
8550276Speter|   Function      :  static void *Copy_Enum_Type( const void * argp )
8650276Speter|
8750276Speter|   Description   :  Copy structure for enumeration type argument.
8850276Speter|
8950276Speter|   Return Values :  Pointer to argument structure or NULL on error.
9050276Speter+--------------------------------------------------------------------------*/
91166124Srafanstatic void *
92166124SrafanCopy_Enum_Type(const void *argp)
9350276Speter{
9450276Speter  enumARG *result = (enumARG *)0;
9550276Speter
9650276Speter  if (argp)
9750276Speter    {
9866963Speter      const enumARG *ap = (const enumARG *)argp;
9966963Speter
100174993Srafan      result = typeMalloc(enumARG, 1);
101166124Srafan
10250276Speter      if (result)
103174993Srafan	{
104174993Srafan	  T((T_CREATE("enumARG %p"), result));
105174993Srafan	  *result = *ap;
106174993Srafan	}
10750276Speter    }
10850276Speter  return (void *)result;
10950276Speter}
11050276Speter
11150276Speter/*---------------------------------------------------------------------------
11250276Speter|   Facility      :  libnform
11350276Speter|   Function      :  static void Free_Enum_Type( void * argp )
11450276Speter|
11550276Speter|   Description   :  Free structure for enumeration type argument.
11650276Speter|
11750276Speter|   Return Values :  -
11850276Speter+--------------------------------------------------------------------------*/
119166124Srafanstatic void
120166124SrafanFree_Enum_Type(void *argp)
12150276Speter{
122166124Srafan  if (argp)
12350276Speter    free(argp);
12450276Speter}
12550276Speter
12650276Speter#define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++
12750276Speter#define NOMATCH 0
12850276Speter#define PARTIAL 1
12950276Speter#define EXACT   2
13050276Speter
13150276Speter/*---------------------------------------------------------------------------
13250276Speter|   Facility      :  libnform
13350276Speter|   Function      :  static int Compare(const unsigned char * s,
13450276Speter|                                       const unsigned char * buf,
13550276Speter|                                       bool  ccase )
13650276Speter|
137166124Srafan|   Description   :  Check whether or not the text in 'buf' matches the
13850276Speter|                    text in 's', at least partial.
13950276Speter|
14050276Speter|   Return Values :  NOMATCH   - buffer doesn't match
14150276Speter|                    PARTIAL   - buffer matches partially
14250276Speter|                    EXACT     - buffer matches exactly
14350276Speter+--------------------------------------------------------------------------*/
144166124Srafanstatic int
145166124SrafanCompare(const unsigned char *s, const unsigned char *buf,
146166124Srafan	bool ccase)
14750276Speter{
148166124Srafan  SKIP_SPACE(buf);		/* Skip leading spaces in both texts */
14950276Speter  SKIP_SPACE(s);
15050276Speter
151166124Srafan  if (*buf == '\0')
15250276Speter    {
153166124Srafan      return (((*s) != '\0') ? NOMATCH : EXACT);
154166124Srafan    }
155166124Srafan  else
15650276Speter    {
15750276Speter      if (ccase)
15850276Speter	{
159166124Srafan	  while (*s++ == *buf)
16050276Speter	    {
161166124Srafan	      if (*buf++ == '\0')
162166124Srafan		return EXACT;
163166124Srafan	    }
164166124Srafan	}
165166124Srafan      else
16650276Speter	{
167166124Srafan	  while (toupper(*s++) == toupper(*buf))
16850276Speter	    {
169166124Srafan	      if (*buf++ == '\0')
170166124Srafan		return EXACT;
17150276Speter	    }
17250276Speter	}
17350276Speter    }
17450276Speter  /* At this location buf points to the first character where it no longer
17550276Speter     matches with s. So if only blanks are following, we have a partial
17650276Speter     match otherwise there is no match */
17750276Speter  SKIP_SPACE(buf);
178166124Srafan  if (*buf)
17950276Speter    return NOMATCH;
18050276Speter
18150276Speter  /* If it happens that the reference buffer is at its end, the partial
18250276Speter     match is actually an exact match. */
183166124Srafan  return ((s[-1] != '\0') ? PARTIAL : EXACT);
18450276Speter}
18550276Speter
18650276Speter/*---------------------------------------------------------------------------
18750276Speter|   Facility      :  libnform
18850276Speter|   Function      :  static bool Check_Enum_Field(
18950276Speter|                                      FIELD * field,
19050276Speter|                                      const void  * argp)
19150276Speter|
19250276Speter|   Description   :  Validate buffer content to be a valid enumeration value
19350276Speter|
19450276Speter|   Return Values :  TRUE  - field is valid
19550276Speter|                    FALSE - field is invalid
19650276Speter+--------------------------------------------------------------------------*/
197166124Srafanstatic bool
198166124SrafanCheck_Enum_Field(FIELD *field, const void *argp)
19950276Speter{
200166124Srafan  char **kwds = ((const enumARG *)argp)->kwds;
201166124Srafan  bool ccase = ((const enumARG *)argp)->checkcase;
202166124Srafan  bool unique = ((const enumARG *)argp)->checkunique;
203166124Srafan  unsigned char *bp = (unsigned char *)field_buffer(field, 0);
20450276Speter  char *s, *t, *p;
20550276Speter  int res;
206166124Srafan
207166124Srafan  while (kwds && (s = (*kwds++)))
20850276Speter    {
209166124Srafan      if ((res = Compare((unsigned char *)s, bp, ccase)) != NOMATCH)
21050276Speter	{
211166124Srafan	  p = t = s;		/* t is at least a partial match */
212166124Srafan	  if ((unique && res != EXACT))
21350276Speter	    {
214166124Srafan	      while (kwds && (p = *kwds++))
21550276Speter		{
216166124Srafan		  if ((res = Compare((unsigned char *)p, bp, ccase)) != NOMATCH)
21750276Speter		    {
218166124Srafan		      if (res == EXACT)
21950276Speter			{
22050276Speter			  t = p;
22150276Speter			  break;
22250276Speter			}
22350276Speter		      else
22450276Speter			t = (char *)0;
22550276Speter		    }
22650276Speter		}
227166124Srafan	    }
22850276Speter	  if (t)
22950276Speter	    {
230166124Srafan	      set_field_buffer(field, 0, t);
23150276Speter	      return TRUE;
23250276Speter	    }
23350276Speter	  if (!p)
23450276Speter	    break;
23550276Speter	}
23650276Speter    }
23750276Speter  return FALSE;
23850276Speter}
23950276Speter
240166124Srafanstatic const char *dummy[] =
241166124Srafan{(char *)0};
24250276Speter
24350276Speter/*---------------------------------------------------------------------------
24450276Speter|   Facility      :  libnform
24550276Speter|   Function      :  static bool Next_Enum(FIELD * field,
24650276Speter|                                          const void * argp)
24750276Speter|
24850276Speter|   Description   :  Check for the next enumeration value
24950276Speter|
25050276Speter|   Return Values :  TRUE  - next value found and loaded
25150276Speter|                    FALSE - no next value loaded
25250276Speter+--------------------------------------------------------------------------*/
253166124Srafanstatic bool
254166124SrafanNext_Enum(FIELD *field, const void *argp)
25550276Speter{
25650276Speter  const enumARG *args = (const enumARG *)argp;
257166124Srafan  char **kwds = args->kwds;
258166124Srafan  bool ccase = args->checkcase;
259166124Srafan  int cnt = args->count;
260166124Srafan  unsigned char *bp = (unsigned char *)field_buffer(field, 0);
26150276Speter
262166124Srafan  if (kwds)
263166124Srafan    {
264166124Srafan      while (cnt--)
265166124Srafan	{
266166124Srafan	  if (Compare((unsigned char *)(*kwds++), bp, ccase) == EXACT)
267166124Srafan	    break;
268166124Srafan	}
269166124Srafan      if (cnt <= 0)
270166124Srafan	kwds = args->kwds;
271166124Srafan      if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT))
272166124Srafan	{
273166124Srafan	  set_field_buffer(field, 0, *kwds);
274166124Srafan	  return TRUE;
275166124Srafan	}
276166124Srafan    }
27750276Speter  return FALSE;
27850276Speter}
27950276Speter
28050276Speter/*---------------------------------------------------------------------------
28150276Speter|   Facility      :  libnform
28250276Speter|   Function      :  static bool Previous_Enum(
28350276Speter|                                          FIELD * field,
28450276Speter|                                          const void * argp)
28550276Speter|
28650276Speter|   Description   :  Check for the previous enumeration value
28750276Speter|
28850276Speter|   Return Values :  TRUE  - previous value found and loaded
28950276Speter|                    FALSE - no previous value loaded
29050276Speter+--------------------------------------------------------------------------*/
291166124Srafanstatic bool
292166124SrafanPrevious_Enum(FIELD *field, const void *argp)
29350276Speter{
29450276Speter  const enumARG *args = (const enumARG *)argp;
295166124Srafan  int cnt = args->count;
296166124Srafan  char **kwds = &args->kwds[cnt - 1];
297166124Srafan  bool ccase = args->checkcase;
298166124Srafan  unsigned char *bp = (unsigned char *)field_buffer(field, 0);
29950276Speter
300166124Srafan  if (kwds)
301166124Srafan    {
302166124Srafan      while (cnt--)
303166124Srafan	{
304166124Srafan	  if (Compare((unsigned char *)(*kwds--), bp, ccase) == EXACT)
305166124Srafan	    break;
306166124Srafan	}
307166124Srafan
308166124Srafan      if (cnt <= 0)
309166124Srafan	kwds = &args->kwds[args->count - 1];
310166124Srafan
311166124Srafan      if ((cnt >= 0) || (Compare((const unsigned char *)dummy, bp, ccase) == EXACT))
312166124Srafan	{
313166124Srafan	  set_field_buffer(field, 0, *kwds);
314166124Srafan	  return TRUE;
315166124Srafan	}
316166124Srafan    }
31750276Speter  return FALSE;
31850276Speter}
31950276Speter
320166124Srafanstatic FIELDTYPE typeENUM =
321166124Srafan{
32250276Speter  _HAS_ARGS | _HAS_CHOICE | _RESIDENT,
323166124Srafan  1,				/* this is mutable, so we can't be const */
32450276Speter  (FIELDTYPE *)0,
32550276Speter  (FIELDTYPE *)0,
32650276Speter  Make_Enum_Type,
32750276Speter  Copy_Enum_Type,
32850276Speter  Free_Enum_Type,
32950276Speter  Check_Enum_Field,
33050276Speter  NULL,
33150276Speter  Next_Enum,
33250276Speter  Previous_Enum
33350276Speter};
33450276Speter
335166124SrafanNCURSES_EXPORT_VAR(FIELDTYPE *)
336166124SrafanTYPE_ENUM = &typeENUM;
33750276Speter
33850276Speter/* fty_enum.c ends here */
339