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 /*LINTLIBRARY*/
32
33 #include <sys/types.h>
34 #include <stdlib.h>
35 #include "utility.h"
36
37 /*
38 * TYPE_ENUM standard type
39 *
40 * usage:
41 * set_field_type(f, TYPE_ENUM, list, checkcase, checkuniq);
42 *
43 * char ** list; list of acceptable strings
44 * int checkcase; TRUE - upper/lower case is significant
45 * int checkuniq; TRUE - unique match required
46 *
47 */
48 typedef struct {
49
50 char ** list;
51 int checkcase;
52 int checkuniq;
53 int count;
54 } ENUM;
55
56 static char * make_enum(va_list *);
57 static char * copy_enum(char *);
58 static void free_enum(char *);
59 static int fcheck_enum(FIELD *, char *);
60 static int next_enum(FIELD *, char *);
61 static int prev_enum(FIELD *, char *);
62
63 static FIELDTYPE typeENUM =
64 {
65 ARGS | CHOICE, /* status */
66 1, /* ref */
67 (FIELDTYPE *) 0, /* left */
68 (FIELDTYPE *) 0, /* right */
69 make_enum, /* makearg */
70 copy_enum, /* copyarg */
71 free_enum, /* freearg */
72 fcheck_enum, /* fcheck */
73 (PTF_int) 0, /* ccheck */
74 next_enum, /* next */
75 prev_enum, /* prev */
76 };
77
78 FIELDTYPE * TYPE_ENUM = &typeENUM;
79
80 static char *
make_enum(va_list * ap)81 make_enum(va_list *ap)
82 {
83 ENUM * n;
84
85 if (Alloc(n, ENUM)) {
86 char ** v;
87
88 n -> list = va_arg(*ap, char **);
89 n -> checkcase = va_arg(*ap, int);
90 n -> checkuniq = va_arg(*ap, int);
91
92 for (v = n -> list; *v; ++v)
93 ;
94 n -> count = (int) (v - n -> list);
95 }
96 return ((char *) n);
97 }
98
99 static char *
copy_enum(char * arg)100 copy_enum(char *arg)
101 {
102 ENUM * n;
103
104 if (Alloc(n, ENUM))
105 *n = *((ENUM *) arg);
106 return ((char *) n);
107 }
108
109 static void
free_enum(char * arg)110 free_enum(char *arg)
111 {
112 Free(arg);
113 }
114
115 #define NO_MATCH 0
116 #define PARTIAL_MATCH 1
117 #define EXACT_MATCH 2
118
119 static int
cmp(char * x,char * v,int checkcase)120 cmp(char *x, char *v, int checkcase)
121 {
122 while (*v && *v == ' ') /* remove leading blanks */
123 ++v;
124 while (*x && *x == ' ') /* remove leading blanks */
125 ++x;
126
127 if (*v == '\0')
128 return (*x == '\0' ? EXACT_MATCH : NO_MATCH);
129
130 if (checkcase) { /* case is significant */
131 while (*x++ == *v)
132 if (*v++ == '\0')
133 return (EXACT_MATCH);
134 } else { /* ignore case */
135 while (toupper (*x++) == toupper (*v))
136 if (*v++ == '\0')
137 return (EXACT_MATCH);
138 }
139 while (*v && *v == ' ') /* remove trailing blanks */
140 ++v;
141 if (*v)
142 return (NO_MATCH);
143 else
144 return (*--x ? PARTIAL_MATCH : EXACT_MATCH);
145 }
146
147 static int
fcheck_enum(FIELD * f,char * arg)148 fcheck_enum(FIELD *f, char *arg)
149 {
150 ENUM * n = (ENUM *) arg;
151 char ** list = n -> list;
152 int checkcase = n -> checkcase;
153 int checkuniq = n -> checkuniq;
154 int m;
155 char * v = field_buffer(f, 0);
156 char * x;
157
158 while (x = *list++)
159 if (m = cmp(x, v, checkcase)) {
160 char * value = x;
161
162 if (checkuniq && m != EXACT_MATCH)
163 while (x = *list++)
164 if (m = cmp(x, v, checkcase)) {
165 if (m == EXACT_MATCH) {
166 value = x;
167 break;
168 }
169 else
170 value = (char *) 0;
171 }
172 if (! value)
173 return (FALSE);
174
175 (void) set_field_buffer(f, 0, value);
176 return (TRUE);
177 }
178
179 return (FALSE);
180 }
181
182 static int
next_enum(FIELD * f,char * arg)183 next_enum(FIELD *f, char *arg)
184 {
185 ENUM * n = (ENUM *) arg;
186 char ** list = n -> list;
187 int checkcase = n -> checkcase;
188 int count = n -> count;
189 char * v = field_buffer(f, 0);
190
191 while (count--)
192 if (cmp(*list++, v, checkcase) == EXACT_MATCH)
193 break;
194 if (count <= 0)
195 list = n -> list;
196
197 if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) {
198 (void) set_field_buffer(f, 0, *list);
199 return (TRUE);
200 }
201 return (FALSE);
202 }
203
204 static int
prev_enum(FIELD * f,char * arg)205 prev_enum(FIELD *f, char *arg)
206 {
207 ENUM * n = (ENUM *) arg;
208 char ** list = n -> list + n -> count - 1;
209 int checkcase = n -> checkcase;
210 int count = n -> count;
211 char * v = field_buffer(f, 0);
212
213 while (count--)
214 if (cmp(*list--, v, checkcase) == EXACT_MATCH)
215 break;
216 if (count <= 0)
217 list = n -> list + n -> count - 1;
218
219 if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) {
220 (void) set_field_buffer(f, 0, *list);
221 return (TRUE);
222 }
223 return (FALSE);
224 }
225