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