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 *
make_enum(va_list * ap)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 *
copy_enum(char * arg)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
free_enum(char * arg)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
cmp(char * x,char * v,int checkcase)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
fcheck_enum(FIELD * f,char * arg)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
next_enum(FIELD * f,char * arg)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
prev_enum(FIELD * f,char * arg)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