xref: /illumos-gate/usr/src/lib/libeti/form/common/ty_enum.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1988 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  *      Copyright (c) 1997, by Sun Microsystems, Inc.
28  *      All rights reserved.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.2	*/
32 
33 /*LINTLIBRARY*/
34 
35 #include <sys/types.h>
36 #include <stdlib.h>
37 #include "utility.h"
38 
39 /*
40  *	TYPE_ENUM standard type
41  *
42  *	usage:
43  *		set_field_type(f, TYPE_ENUM, list, checkcase, checkuniq);
44  *
45  *		char ** list;	list of acceptable strings
46  *		int checkcase;	TRUE - upper/lower case is significant
47  *		int checkuniq;	TRUE - unique match required
48  *
49  */
50 typedef struct {
51 
52 	char **	list;
53 	int	checkcase;
54 	int	checkuniq;
55 	int	count;
56 } ENUM;
57 
58 static char * make_enum(va_list *);
59 static char * copy_enum(char *);
60 static void free_enum(char *);
61 static int fcheck_enum(FIELD *, char *);
62 static int next_enum(FIELD *, char *);
63 static int prev_enum(FIELD *, char *);
64 
65 static FIELDTYPE typeENUM =
66 {
67 				ARGS | CHOICE,		/* status	*/
68 				1,			/* ref		*/
69 				(FIELDTYPE *) 0,	/* left		*/
70 				(FIELDTYPE *) 0,	/* right	*/
71 				make_enum,		/* makearg	*/
72 				copy_enum,		/* copyarg	*/
73 				free_enum,		/* freearg	*/
74 				fcheck_enum,		/* fcheck	*/
75 				(PTF_int) 0,		/* ccheck	*/
76 				next_enum,		/* next		*/
77 				prev_enum,		/* prev		*/
78 };
79 
80 FIELDTYPE * TYPE_ENUM = &typeENUM;
81 
82 static char *
83 make_enum(va_list *ap)
84 {
85 	ENUM * n;
86 
87 	if (Alloc(n, ENUM)) {
88 		char **		v;
89 
90 		n -> list	= va_arg(*ap, char **);
91 		n -> checkcase	= va_arg(*ap, int);
92 		n -> checkuniq	= va_arg(*ap, int);
93 
94 		for (v = n -> list; *v; ++v)
95 			;
96 		n -> count = (int) (v - n -> list);
97 	}
98 	return ((char *) n);
99 }
100 
101 static char *
102 copy_enum(char *arg)
103 {
104 	ENUM * n;
105 
106 	if (Alloc(n, ENUM))
107 		*n = *((ENUM *) arg);
108 	return ((char *) n);
109 }
110 
111 static void
112 free_enum(char *arg)
113 {
114 	Free(arg);
115 }
116 
117 #define	NO_MATCH		0
118 #define	PARTIAL_MATCH		1
119 #define	EXACT_MATCH		2
120 
121 static int
122 cmp(char *x, char *v, int checkcase)
123 {
124 	while (*v && *v == ' ')			/* remove leading blanks */
125 		++v;
126 	while (*x && *x == ' ')			/* remove leading blanks */
127 		++x;
128 
129 	if (*v == '\0')
130 		return (*x == '\0' ? EXACT_MATCH : NO_MATCH);
131 
132 	if (checkcase) {			/* case is significant */
133 		while (*x++ == *v)
134 			if (*v++ == '\0')
135 				return (EXACT_MATCH);
136 	} else {				/* ignore case */
137 		while (toupper (*x++) == toupper (*v))
138 			if (*v++ == '\0')
139 				return (EXACT_MATCH);
140 	}
141 	while (*v && *v == ' ')			/* remove trailing blanks */
142 		++v;
143 	if (*v)
144 		return (NO_MATCH);
145 	else
146 		return (*--x ? PARTIAL_MATCH : EXACT_MATCH);
147 }
148 
149 static int
150 fcheck_enum(FIELD *f, char *arg)
151 {
152 	ENUM *		n		= (ENUM *) arg;
153 	char **		list		= n -> list;
154 	int		checkcase	= n -> checkcase;
155 	int		checkuniq	= n -> checkuniq;
156 	int		m;
157 	char *		v		= field_buffer(f, 0);
158 	char *		x;
159 
160 	while (x = *list++)
161 		if (m = cmp(x, v, checkcase)) {
162 			char * value = x;
163 
164 			if (checkuniq && m != EXACT_MATCH)
165 				while (x = *list++)
166 					if (m = cmp(x, v, checkcase)) {
167 						if (m == EXACT_MATCH) {
168 							value = x;
169 							break;
170 						}
171 						else
172 							value = (char *) 0;
173 					}
174 			if (! value)
175 				return (FALSE);
176 
177 			(void) set_field_buffer(f, 0, value);
178 			return (TRUE);
179 		}
180 
181 	return (FALSE);
182 }
183 
184 static int
185 next_enum(FIELD *f, char *arg)
186 {
187 	ENUM *		n		= (ENUM *) arg;
188 	char **		list		= n -> list;
189 	int		checkcase	= n -> checkcase;
190 	int		count		= n -> count;
191 	char *		v		= field_buffer(f, 0);
192 
193 	while (count--)
194 		if (cmp(*list++, v, checkcase) == EXACT_MATCH)
195 			break;
196 	if (count <= 0)
197 		list = n -> list;
198 
199 	if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) {
200 		(void) set_field_buffer(f, 0, *list);
201 		return (TRUE);
202 	}
203 	return (FALSE);
204 }
205 
206 static int
207 prev_enum(FIELD *f, char *arg)
208 {
209 	ENUM *		n		= (ENUM *) arg;
210 	char **		list		= n -> list + n -> count - 1;
211 	int		checkcase	= n -> checkcase;
212 	int		count		= n -> count;
213 	char *		v		= field_buffer(f, 0);
214 
215 	while (count--)
216 		if (cmp(*list--, v, checkcase) == EXACT_MATCH)
217 			break;
218 	if (count <= 0)
219 		list = n -> list + n -> count - 1;
220 
221 	if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) {
222 		(void) set_field_buffer(f, 0, *list);
223 		return (TRUE);
224 	}
225 	return (FALSE);
226 }
227