xref: /freebsd/contrib/ncurses/form/fty_enum.c (revision 15589c42)
1 
2 /*
3  * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
4  * You may freely copy it for use as a template for your own field types.
5  * If you develop a field type that might be of general use, please send
6  * it back to the ncurses maintainers for inclusion in the next version.
7  */
8 /***************************************************************************
9 *                                                                          *
10 *  Author : Juergen Pfeifer, juergen.pfeifer@gmx.net                       *
11 *                                                                          *
12 ***************************************************************************/
13 
14 #include "form.priv.h"
15 
16 MODULE_ID("$Id: fty_enum.c,v 1.11 2000/03/19 01:09:56 Bruno.Haible Exp $")
17 
18 typedef struct {
19   char **kwds;
20   int  count;
21   bool checkcase;
22   bool checkunique;
23 } enumARG;
24 
25 /*---------------------------------------------------------------------------
26 |   Facility      :  libnform
27 |   Function      :  static void *Make_Enum_Type( va_list * ap )
28 |
29 |   Description   :  Allocate structure for enumeration type argument.
30 |
31 |   Return Values :  Pointer to argument structure or NULL on error
32 +--------------------------------------------------------------------------*/
33 static void *Make_Enum_Type(va_list * ap)
34 {
35   enumARG *argp = (enumARG *)malloc(sizeof(enumARG));
36   char **kp;
37   int cnt=0;
38 
39   if (argp)
40     {
41       int ccase, cunique;
42       argp->kwds        = va_arg(*ap,char **);
43       ccase             = va_arg(*ap,int);
44       cunique           = va_arg(*ap,int);
45       argp->checkcase   = ccase   ? TRUE : FALSE;
46       argp->checkunique = cunique ? TRUE : FALSE;
47 
48       kp = argp->kwds;
49       while( (*kp++) ) cnt++;
50       argp->count = cnt;
51     }
52   return (void *)argp;
53 }
54 
55 /*---------------------------------------------------------------------------
56 |   Facility      :  libnform
57 |   Function      :  static void *Copy_Enum_Type( const void * argp )
58 |
59 |   Description   :  Copy structure for enumeration type argument.
60 |
61 |   Return Values :  Pointer to argument structure or NULL on error.
62 +--------------------------------------------------------------------------*/
63 static void *Copy_Enum_Type(const void * argp)
64 {
65   const enumARG *ap = (const enumARG *)argp;
66   enumARG *result = (enumARG *)0;
67 
68   if (argp)
69     {
70       result = (enumARG *)malloc(sizeof(enumARG));
71       if (result)
72 	*result = *ap;
73     }
74   return (void *)result;
75 }
76 
77 /*---------------------------------------------------------------------------
78 |   Facility      :  libnform
79 |   Function      :  static void Free_Enum_Type( void * argp )
80 |
81 |   Description   :  Free structure for enumeration type argument.
82 |
83 |   Return Values :  -
84 +--------------------------------------------------------------------------*/
85 static void Free_Enum_Type(void * argp)
86 {
87   if (argp)
88     free(argp);
89 }
90 
91 #define SKIP_SPACE(x) while(((*(x))!='\0') && (is_blank(*(x)))) (x)++
92 #define NOMATCH 0
93 #define PARTIAL 1
94 #define EXACT   2
95 
96 /*---------------------------------------------------------------------------
97 |   Facility      :  libnform
98 |   Function      :  static int Compare(const unsigned char * s,
99 |                                       const unsigned char * buf,
100 |                                       bool  ccase )
101 |
102 |   Description   :  Check wether or not the text in 'buf' matches the
103 |                    text in 's', at least partial.
104 |
105 |   Return Values :  NOMATCH   - buffer doesn't match
106 |                    PARTIAL   - buffer matches partially
107 |                    EXACT     - buffer matches exactly
108 +--------------------------------------------------------------------------*/
109 static int Compare(const unsigned char *s, const unsigned char *buf,
110 		   bool ccase)
111 {
112   SKIP_SPACE(buf); /* Skip leading spaces in both texts */
113   SKIP_SPACE(s);
114 
115   if (*buf=='\0')
116     {
117       return (((*s)!='\0') ? NOMATCH : EXACT);
118     }
119   else
120     {
121       if (ccase)
122 	{
123 	  while(*s++ == *buf)
124 	    {
125 	      if (*buf++=='\0') return EXACT;
126 	    }
127 	}
128       else
129 	{
130 	  while(toupper(*s++)==toupper(*buf))
131 	    {
132 	      if (*buf++=='\0') return EXACT;
133 	    }
134 	}
135     }
136   /* At this location buf points to the first character where it no longer
137      matches with s. So if only blanks are following, we have a partial
138      match otherwise there is no match */
139   SKIP_SPACE(buf);
140   if (*buf)
141     return NOMATCH;
142 
143   /* If it happens that the reference buffer is at its end, the partial
144      match is actually an exact match. */
145   return ((s[-1]!='\0') ? PARTIAL : EXACT);
146 }
147 
148 /*---------------------------------------------------------------------------
149 |   Facility      :  libnform
150 |   Function      :  static bool Check_Enum_Field(
151 |                                      FIELD * field,
152 |                                      const void  * argp)
153 |
154 |   Description   :  Validate buffer content to be a valid enumeration value
155 |
156 |   Return Values :  TRUE  - field is valid
157 |                    FALSE - field is invalid
158 +--------------------------------------------------------------------------*/
159 static bool Check_Enum_Field(FIELD * field, const void  * argp)
160 {
161   char **kwds       = ((const enumARG *)argp)->kwds;
162   bool ccase        = ((const enumARG *)argp)->checkcase;
163   bool unique       = ((const enumARG *)argp)->checkunique;
164   unsigned char *bp = (unsigned char *)field_buffer(field,0);
165   char *s, *t, *p;
166   int res;
167 
168   while( (s=(*kwds++)) )
169     {
170       if ((res=Compare((unsigned char *)s,bp,ccase))!=NOMATCH)
171 	{
172 	  p=t=s; /* t is at least a partial match */
173 	  if ((unique && res!=EXACT))
174 	    {
175 	      while( (p = *kwds++) )
176 		{
177 		  if ((res=Compare((unsigned char *)p,bp,ccase))!=NOMATCH)
178 		    {
179 		      if (res==EXACT)
180 			{
181 			  t = p;
182 			  break;
183 			}
184 		      else
185 			t = (char *)0;
186 		    }
187 		}
188 	    }
189 	  if (t)
190 	    {
191 	      set_field_buffer(field,0,t);
192 	      return TRUE;
193 	    }
194 	  if (!p)
195 	    break;
196 	}
197     }
198   return FALSE;
199 }
200 
201 static const char *dummy[] = { (char *)0 };
202 
203 /*---------------------------------------------------------------------------
204 |   Facility      :  libnform
205 |   Function      :  static bool Next_Enum(FIELD * field,
206 |                                          const void * argp)
207 |
208 |   Description   :  Check for the next enumeration value
209 |
210 |   Return Values :  TRUE  - next value found and loaded
211 |                    FALSE - no next value loaded
212 +--------------------------------------------------------------------------*/
213 static bool Next_Enum(FIELD * field, const void * argp)
214 {
215   const enumARG *args = (const enumARG *)argp;
216   char **kwds       = args->kwds;
217   bool ccase        = args->checkcase;
218   int cnt           = args->count;
219   unsigned char *bp = (unsigned char *)field_buffer(field,0);
220 
221   while(cnt--)
222     {
223       if (Compare((unsigned char *)(*kwds++),bp,ccase)==EXACT)
224 	break;
225     }
226   if (cnt<=0)
227     kwds = args->kwds;
228   if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))
229     {
230       set_field_buffer(field,0,*kwds);
231       return TRUE;
232     }
233   return FALSE;
234 }
235 
236 /*---------------------------------------------------------------------------
237 |   Facility      :  libnform
238 |   Function      :  static bool Previous_Enum(
239 |                                          FIELD * field,
240 |                                          const void * argp)
241 |
242 |   Description   :  Check for the previous enumeration value
243 |
244 |   Return Values :  TRUE  - previous value found and loaded
245 |                    FALSE - no previous value loaded
246 +--------------------------------------------------------------------------*/
247 static bool Previous_Enum(FIELD * field, const void * argp)
248 {
249   const enumARG *args = (const enumARG *)argp;
250   int cnt       = args->count;
251   char **kwds   = &args->kwds[cnt-1];
252   bool ccase    = args->checkcase;
253   unsigned char *bp = (unsigned char *)field_buffer(field,0);
254 
255   while(cnt--)
256     {
257       if (Compare((unsigned char *)(*kwds--),bp,ccase)==EXACT)
258 	break;
259     }
260 
261   if (cnt<=0)
262     kwds  = &args->kwds[args->count-1];
263 
264   if ((cnt>=0) || (Compare((const unsigned char *)dummy,bp,ccase)==EXACT))
265     {
266       set_field_buffer(field,0,*kwds);
267       return TRUE;
268     }
269   return FALSE;
270 }
271 
272 
273 static FIELDTYPE typeENUM = {
274   _HAS_ARGS | _HAS_CHOICE | _RESIDENT,
275   1,                           /* this is mutable, so we can't be const */
276   (FIELDTYPE *)0,
277   (FIELDTYPE *)0,
278   Make_Enum_Type,
279   Copy_Enum_Type,
280   Free_Enum_Type,
281   Check_Enum_Field,
282   NULL,
283   Next_Enum,
284   Previous_Enum
285 };
286 
287 FIELDTYPE* TYPE_ENUM = &typeENUM;
288 
289 /* fty_enum.c ends here */
290