xref: /onnv-gate/usr/src/lib/libdhcputil/common/dhcp_symbol.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdlib.h>
30*0Sstevel@tonic-gate #include <ctype.h>
31*0Sstevel@tonic-gate #include <strings.h>
32*0Sstevel@tonic-gate #include <limits.h>
33*0Sstevel@tonic-gate #include <errno.h>
34*0Sstevel@tonic-gate #include <dhcp_impl.h>
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include "dhcp_symbol.h"
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate /*
39*0Sstevel@tonic-gate  * The following structure and table are used to define the attributes
40*0Sstevel@tonic-gate  * of a DHCP symbol category.
41*0Sstevel@tonic-gate  */
42*0Sstevel@tonic-gate typedef struct dsym_cat {
43*0Sstevel@tonic-gate 	char		*dc_string;	/* string value for the category */
44*0Sstevel@tonic-gate 	int		dc_minlen;	/* min. chars of dc_string to match */
45*0Sstevel@tonic-gate 	dsym_category_t	dc_id;		/* numerical value for the category */
46*0Sstevel@tonic-gate 	boolean_t	dc_dhcptab;	/* valid for dhcptab use? */
47*0Sstevel@tonic-gate 	ushort_t	dc_min;		/* minimum valid code */
48*0Sstevel@tonic-gate 	ushort_t	dc_max;		/* maximum valid code */
49*0Sstevel@tonic-gate } dsym_cat_t;
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate static dsym_cat_t cats[DSYM_CATEGORY_NUM] = {
52*0Sstevel@tonic-gate 	{ "Extend", 6, DSYM_EXTEND, B_TRUE, DHCP_LAST_STD + 1,
53*0Sstevel@tonic-gate 		DHCP_SITE_OPT - 1 },
54*0Sstevel@tonic-gate 	{ "Vendor=", 6, DSYM_VENDOR, B_TRUE, DHCP_FIRST_OPT,
55*0Sstevel@tonic-gate 		DHCP_LAST_OPT },
56*0Sstevel@tonic-gate 	{ "Site", 4, DSYM_SITE, B_TRUE, DHCP_SITE_OPT, DHCP_LAST_OPT },
57*0Sstevel@tonic-gate 	{ "Standard", 8, DSYM_STANDARD, B_FALSE, DHCP_FIRST_OPT,
58*0Sstevel@tonic-gate 	    DHCP_LAST_STD },
59*0Sstevel@tonic-gate 	{ "Field", 5, DSYM_FIELD, B_FALSE, CD_PACKET_START,
60*0Sstevel@tonic-gate 		CD_PACKET_END },
61*0Sstevel@tonic-gate 	{ "Internal", 8, DSYM_INTERNAL, B_FALSE, CD_INTRNL_START,
62*0Sstevel@tonic-gate 	    CD_INTRNL_END }
63*0Sstevel@tonic-gate };
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate /*
66*0Sstevel@tonic-gate  * The following structure and table are used to define the attributes
67*0Sstevel@tonic-gate  * of a DHCP symbol type.
68*0Sstevel@tonic-gate  */
69*0Sstevel@tonic-gate typedef struct dsym_type {
70*0Sstevel@tonic-gate 	char		*dt_string;	/* string value for the type */
71*0Sstevel@tonic-gate 	dsym_cdtype_t	dt_id;		/* numerical value for the type */
72*0Sstevel@tonic-gate 	boolean_t	dt_dhcptab;	/* valid for dhcptab use? */
73*0Sstevel@tonic-gate } dsym_type_t;
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate static dsym_type_t types[DSYM_CDTYPE_NUM] = {
76*0Sstevel@tonic-gate 	{ "ASCII", DSYM_ASCII, B_TRUE },
77*0Sstevel@tonic-gate 	{ "OCTET", DSYM_OCTET, B_TRUE },
78*0Sstevel@tonic-gate 	{ "IP", DSYM_IP, B_TRUE },
79*0Sstevel@tonic-gate 	{ "NUMBER", DSYM_NUMBER, B_TRUE },
80*0Sstevel@tonic-gate 	{ "BOOL", DSYM_BOOL, B_TRUE },
81*0Sstevel@tonic-gate 	{ "INCLUDE", DSYM_INCLUDE, B_FALSE },
82*0Sstevel@tonic-gate 	{ "UNUMBER8", DSYM_UNUMBER8, B_TRUE },
83*0Sstevel@tonic-gate 	{ "UNUMBER16", DSYM_UNUMBER16, B_TRUE },
84*0Sstevel@tonic-gate 	{ "UNUMBER32", DSYM_UNUMBER32, B_TRUE },
85*0Sstevel@tonic-gate 	{ "UNUMBER64", DSYM_UNUMBER64, B_TRUE },
86*0Sstevel@tonic-gate 	{ "SNUMBER8", DSYM_SNUMBER8, B_TRUE },
87*0Sstevel@tonic-gate 	{ "SNUMBER16", DSYM_SNUMBER16, B_TRUE },
88*0Sstevel@tonic-gate 	{ "SNUMBER32", DSYM_SNUMBER32, B_TRUE },
89*0Sstevel@tonic-gate 	{ "SNUMBER64", DSYM_SNUMBER64, B_TRUE }
90*0Sstevel@tonic-gate };
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate /*
93*0Sstevel@tonic-gate  * symbol delimiters and constants
94*0Sstevel@tonic-gate  */
95*0Sstevel@tonic-gate #define	DSYM_CLASS_DEL		" \t\n"
96*0Sstevel@tonic-gate #define	DSYM_FIELD_DEL		","
97*0Sstevel@tonic-gate #define	DSYM_VENDOR_DEL		'='
98*0Sstevel@tonic-gate #define	DSYM_QUOTE		'"'
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * dsym_trim(): trims all whitespace from either side of a string
102*0Sstevel@tonic-gate  *
103*0Sstevel@tonic-gate  *  input: char **: a pointer to a string to trim of whitespace.
104*0Sstevel@tonic-gate  * output: none
105*0Sstevel@tonic-gate  */
106*0Sstevel@tonic-gate static void
107*0Sstevel@tonic-gate dsym_trim(char **str)
108*0Sstevel@tonic-gate {
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	char *tmpstr = *str;
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	/*
113*0Sstevel@tonic-gate 	 * Trim all whitespace from the front of the string.
114*0Sstevel@tonic-gate 	 */
115*0Sstevel@tonic-gate 	while (*tmpstr != '\0' && isspace(*tmpstr)) {
116*0Sstevel@tonic-gate 		tmpstr++;
117*0Sstevel@tonic-gate 	}
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	/*
120*0Sstevel@tonic-gate 	 * Move the str pointer to first non-whitespace char.
121*0Sstevel@tonic-gate 	 */
122*0Sstevel@tonic-gate 	*str = tmpstr;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	/*
125*0Sstevel@tonic-gate 	 * Check case where the string is nothing but whitespace.
126*0Sstevel@tonic-gate 	 */
127*0Sstevel@tonic-gate 	if (*tmpstr == '\0') {
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 		/*
130*0Sstevel@tonic-gate 		 * Trim all whitespace from the end of the string.
131*0Sstevel@tonic-gate 		 */
132*0Sstevel@tonic-gate 		tmpstr = *str + strlen(*str) - 1;
133*0Sstevel@tonic-gate 		while (tmpstr >= *str && isspace(*tmpstr)) {
134*0Sstevel@tonic-gate 			tmpstr--;
135*0Sstevel@tonic-gate 		}
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 		/*
138*0Sstevel@tonic-gate 		 * terminate after last non-whitespace char.
139*0Sstevel@tonic-gate 		 */
140*0Sstevel@tonic-gate 		*(tmpstr+1) = '\0';
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate /*
145*0Sstevel@tonic-gate  * dsym_get_token(): strtok_r() like routine, except consecutive delimiters
146*0Sstevel@tonic-gate  *                   result in an empty string
147*0Sstevel@tonic-gate  *
148*0Sstevel@tonic-gate  *   note: original string is modified
149*0Sstevel@tonic-gate  *
150*0Sstevel@tonic-gate  *  input: char *: string in which to search for tokens
151*0Sstevel@tonic-gate  *         char *: list of possible token delimiter characters
152*0Sstevel@tonic-gate  *         char **: location for next call to routine
153*0Sstevel@tonic-gate  *         boolean_t: should delimiters be ignored if within quoted string?
154*0Sstevel@tonic-gate  * output: char *: token, or NULL if no more tokens
155*0Sstevel@tonic-gate  */
156*0Sstevel@tonic-gate static char *
157*0Sstevel@tonic-gate dsym_get_token(char *str, char *dels, char **lasts, boolean_t quote_support)
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	char *ptr = str;
161*0Sstevel@tonic-gate 	char *del;
162*0Sstevel@tonic-gate 	boolean_t found = B_FALSE;
163*0Sstevel@tonic-gate 	boolean_t in_quote = B_FALSE;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/*
166*0Sstevel@tonic-gate 	 * If incoming string has no tokens return a NULL
167*0Sstevel@tonic-gate 	 * pointer to signify no more tokens.
168*0Sstevel@tonic-gate 	 */
169*0Sstevel@tonic-gate 	if (*ptr == '\0') {
170*0Sstevel@tonic-gate 		return (NULL);
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	/*
174*0Sstevel@tonic-gate 	 * Loop until either a token has been identified or until end
175*0Sstevel@tonic-gate 	 * of string has been reached.
176*0Sstevel@tonic-gate 	 */
177*0Sstevel@tonic-gate 	while (!found && *ptr != '\0') {
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 		/*
180*0Sstevel@tonic-gate 		 * If pointer currently lies within a quoted string,
181*0Sstevel@tonic-gate 		 * then do not check for the delimiter.
182*0Sstevel@tonic-gate 		 */
183*0Sstevel@tonic-gate 		if (!in_quote) {
184*0Sstevel@tonic-gate 			for (del = dels; !found && *del != '\0'; del++) {
185*0Sstevel@tonic-gate 				if (*del == *ptr) {
186*0Sstevel@tonic-gate 					*ptr++ = '\0';
187*0Sstevel@tonic-gate 					found = B_TRUE;
188*0Sstevel@tonic-gate 				}
189*0Sstevel@tonic-gate 			}
190*0Sstevel@tonic-gate 		}
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 		/*
193*0Sstevel@tonic-gate 		 * If the pointer is pointing at a delimiter, then
194*0Sstevel@tonic-gate 		 * check to see if it points to at a quote and update
195*0Sstevel@tonic-gate 		 * the state appropriately.
196*0Sstevel@tonic-gate 		 */
197*0Sstevel@tonic-gate 		if (!found) {
198*0Sstevel@tonic-gate 			if (quote_support && *ptr == DSYM_QUOTE) {
199*0Sstevel@tonic-gate 				in_quote = !in_quote;
200*0Sstevel@tonic-gate 			}
201*0Sstevel@tonic-gate 			ptr++;
202*0Sstevel@tonic-gate 		}
203*0Sstevel@tonic-gate 	}
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	*lasts = ptr;
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	return (str);
208*0Sstevel@tonic-gate }
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate /*
211*0Sstevel@tonic-gate  * dsym_get_long(): given a numeric string, returns its long value
212*0Sstevel@tonic-gate  *
213*0Sstevel@tonic-gate  *  input: const char *: the numeric string
214*0Sstevel@tonic-gate  *         long *: the return location for the long value
215*0Sstevel@tonic-gate  * output: DSYM_SUCCESS, DSYM_VALUE_OUT_OF_RANGE or DSYM_SYNTAX_ERROR
216*0Sstevel@tonic-gate  */
217*0Sstevel@tonic-gate static dsym_errcode_t
218*0Sstevel@tonic-gate dsym_get_long(const char *str, long *val)
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
222*0Sstevel@tonic-gate 	int i;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	for (i = 0; str[i] != '\0'; i++) {
225*0Sstevel@tonic-gate 		if (!isdigit(str[i])) {
226*0Sstevel@tonic-gate 			return (DSYM_SYNTAX_ERROR);
227*0Sstevel@tonic-gate 		}
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	errno = 0;
231*0Sstevel@tonic-gate 	*val = strtol(str, NULL, 10);
232*0Sstevel@tonic-gate 	if (errno != 0) {
233*0Sstevel@tonic-gate 		ret = DSYM_VALUE_OUT_OF_RANGE;
234*0Sstevel@tonic-gate 	}
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	return (ret);
237*0Sstevel@tonic-gate }
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate /*
240*0Sstevel@tonic-gate  * dsym_free_classes(): frees the classes allocated by dsym_parse_classes()
241*0Sstevel@tonic-gate  *
242*0Sstevel@tonic-gate  *  input: dhcp_classes_t *: pointer to structure containing classes to free
243*0Sstevel@tonic-gate  * output: none
244*0Sstevel@tonic-gate  */
245*0Sstevel@tonic-gate void
246*0Sstevel@tonic-gate dsym_free_classes(dhcp_classes_t *classes)
247*0Sstevel@tonic-gate {
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	int i;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	if (classes->dc_names == NULL) {
252*0Sstevel@tonic-gate 		return;
253*0Sstevel@tonic-gate 	}
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	for (i = 0; i < classes->dc_cnt; i++) {
256*0Sstevel@tonic-gate 		free(classes->dc_names[i]);
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	free(classes->dc_names);
260*0Sstevel@tonic-gate 	classes->dc_names = NULL;
261*0Sstevel@tonic-gate 	classes->dc_cnt = 0;
262*0Sstevel@tonic-gate }
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate /*
265*0Sstevel@tonic-gate  * dsym_parse_classes(): given a "Vendor" class string, builds and returns
266*0Sstevel@tonic-gate  *                     the list of vendor classes
267*0Sstevel@tonic-gate  *
268*0Sstevel@tonic-gate  *  input: char *: the "Vendor" class string
269*0Sstevel@tonic-gate  *         dhcp_classes_t *: pointer to the classes structure
270*0Sstevel@tonic-gate  * output: DSYM_SUCCESS, DSYM_INVALID_CAT, DSYM_EXCEEDS_MAX_CLASS_SIZE,
271*0Sstevel@tonic-gate  *         DSYM_EXCEEDS_CLASS_SIZE, DSYM_SYNTAX_ERROR, or DSYM_NO_MEMORY
272*0Sstevel@tonic-gate  */
273*0Sstevel@tonic-gate static dsym_errcode_t
274*0Sstevel@tonic-gate dsym_parse_classes(char *ptr, dhcp_classes_t *classes_ret)
275*0Sstevel@tonic-gate {
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	char **classes = NULL;
278*0Sstevel@tonic-gate 	char *cp;
279*0Sstevel@tonic-gate 	int len;
280*0Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
281*0Sstevel@tonic-gate 	int i;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	while (*ptr != '\0') {
284*0Sstevel@tonic-gate 		if (*ptr == DSYM_VENDOR_DEL) {
285*0Sstevel@tonic-gate 			ptr++;
286*0Sstevel@tonic-gate 			break;
287*0Sstevel@tonic-gate 		}
288*0Sstevel@tonic-gate 		ptr++;
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if (*ptr == '\0') {
292*0Sstevel@tonic-gate 	    return (DSYM_INVALID_CAT);
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	if (strlen(ptr) > DSYM_MAX_CLASS_SIZE) {
296*0Sstevel@tonic-gate 		return (DSYM_EXCEEDS_MAX_CLASS_SIZE);
297*0Sstevel@tonic-gate 	}
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	dsym_trim(&ptr);
300*0Sstevel@tonic-gate 	classes_ret->dc_cnt = 0;
301*0Sstevel@tonic-gate 	for (i = 0; ret == DSYM_SUCCESS; i++) {
302*0Sstevel@tonic-gate 		cp = dsym_get_token(ptr, DSYM_CLASS_DEL, &ptr, B_TRUE);
303*0Sstevel@tonic-gate 		if (cp == NULL) {
304*0Sstevel@tonic-gate 			break;
305*0Sstevel@tonic-gate 		}
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 		len = strlen(cp);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 		if (len == 0) {
310*0Sstevel@tonic-gate 			continue;
311*0Sstevel@tonic-gate 		} else if (len > DSYM_CLASS_SIZE) {
312*0Sstevel@tonic-gate 			ret = DSYM_EXCEEDS_CLASS_SIZE;
313*0Sstevel@tonic-gate 			continue;
314*0Sstevel@tonic-gate 		}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 		if (cp[0] == DSYM_QUOTE && cp[len-1] != DSYM_QUOTE) {
317*0Sstevel@tonic-gate 			ret = DSYM_SYNTAX_ERROR;
318*0Sstevel@tonic-gate 			continue;
319*0Sstevel@tonic-gate 		}
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 		/* Strip off the quotes */
322*0Sstevel@tonic-gate 		if (cp[0] == DSYM_QUOTE) {
323*0Sstevel@tonic-gate 			cp[len-1] = '\0';
324*0Sstevel@tonic-gate 			cp++;
325*0Sstevel@tonic-gate 		}
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 		classes = realloc(classes_ret->dc_names,
328*0Sstevel@tonic-gate 		    (sizeof (char **)) * (classes_ret->dc_cnt + 1));
329*0Sstevel@tonic-gate 		if (classes == NULL ||
330*0Sstevel@tonic-gate 		    (classes[classes_ret->dc_cnt] = strdup(cp))
331*0Sstevel@tonic-gate 		    == NULL) {
332*0Sstevel@tonic-gate 			ret = DSYM_NO_MEMORY;
333*0Sstevel@tonic-gate 			continue;
334*0Sstevel@tonic-gate 		}
335*0Sstevel@tonic-gate 		classes_ret->dc_names = classes;
336*0Sstevel@tonic-gate 		classes_ret->dc_cnt++;
337*0Sstevel@tonic-gate 	}
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	if (ret != DSYM_SUCCESS) {
340*0Sstevel@tonic-gate 		dsym_free_classes(classes_ret);
341*0Sstevel@tonic-gate 	}
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	return (ret);
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate /*
347*0Sstevel@tonic-gate  * dsym_get_cat_by_name(): given a category field, returns the pointer to its
348*0Sstevel@tonic-gate  *                         entry in the internal category table.
349*0Sstevel@tonic-gate  *
350*0Sstevel@tonic-gate  *  input: const char *: the category name
351*0Sstevel@tonic-gate  *         dsym_cat_t *: the return location for the pointer to the table entry
352*0Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
353*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
354*0Sstevel@tonic-gate  */
355*0Sstevel@tonic-gate static dsym_errcode_t
356*0Sstevel@tonic-gate dsym_get_cat_by_name(const char *cat, dsym_cat_t **entry, boolean_t cs)
357*0Sstevel@tonic-gate {
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	dsym_cat_t *entryp = NULL;
360*0Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
361*0Sstevel@tonic-gate 	int cnt = sizeof (cats) / sizeof (dsym_cat_t);
362*0Sstevel@tonic-gate 	int result;
363*0Sstevel@tonic-gate 	int len;
364*0Sstevel@tonic-gate 	int i;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 		len = cats[i].dc_minlen;
369*0Sstevel@tonic-gate 		if (cs) {
370*0Sstevel@tonic-gate 			result = strncmp(cat, cats[i].dc_string, len);
371*0Sstevel@tonic-gate 		} else {
372*0Sstevel@tonic-gate 			result = strncasecmp(cat, cats[i].dc_string, len);
373*0Sstevel@tonic-gate 		}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 		if (result == 0) {
376*0Sstevel@tonic-gate 			entryp = &cats[i];
377*0Sstevel@tonic-gate 			break;
378*0Sstevel@tonic-gate 		}
379*0Sstevel@tonic-gate 	}
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	if (entryp != NULL) {
382*0Sstevel@tonic-gate 		/*
383*0Sstevel@tonic-gate 		 * Special code required for the Vendor category, because we
384*0Sstevel@tonic-gate 		 * allow whitespace between the keyword and the delimiter.
385*0Sstevel@tonic-gate 		 * If there is no delimiter, then this is an illegal category.
386*0Sstevel@tonic-gate 		 */
387*0Sstevel@tonic-gate 		const char *ptr = cat + entryp->dc_minlen;
388*0Sstevel@tonic-gate 		if (entryp->dc_id == DSYM_VENDOR) {
389*0Sstevel@tonic-gate 			while (*ptr != '\0' && isspace(*ptr)) {
390*0Sstevel@tonic-gate 				ptr++;
391*0Sstevel@tonic-gate 			}
392*0Sstevel@tonic-gate 			if (*ptr != DSYM_VENDOR_DEL) {
393*0Sstevel@tonic-gate 				ret = DSYM_INVALID_CAT;
394*0Sstevel@tonic-gate 			}
395*0Sstevel@tonic-gate 		} else {
396*0Sstevel@tonic-gate 			if (*ptr != '\0') {
397*0Sstevel@tonic-gate 				ret = DSYM_INVALID_CAT;
398*0Sstevel@tonic-gate 			}
399*0Sstevel@tonic-gate 		}
400*0Sstevel@tonic-gate 	} else {
401*0Sstevel@tonic-gate 		ret = DSYM_INVALID_CAT;
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
405*0Sstevel@tonic-gate 		*entry = entryp;
406*0Sstevel@tonic-gate 	}
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	return (ret);
409*0Sstevel@tonic-gate }
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate /*
412*0Sstevel@tonic-gate  * dsym_parse_cat(): given a category field, returns the category value
413*0Sstevel@tonic-gate  *                 Note: The category must be a valid dhcptab category.
414*0Sstevel@tonic-gate  *
415*0Sstevel@tonic-gate  *  input: const char *: a category field
416*0Sstevel@tonic-gate  *         dsym_category_t *: the return location for the category value
417*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
418*0Sstevel@tonic-gate  */
419*0Sstevel@tonic-gate static dsym_errcode_t
420*0Sstevel@tonic-gate dsym_parse_cat(const char *field, dsym_category_t *cat)
421*0Sstevel@tonic-gate {
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	dsym_cat_t *entry;
424*0Sstevel@tonic-gate 	int ret;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	ret = dsym_get_cat_by_name(field, &entry, B_TRUE);
427*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
428*0Sstevel@tonic-gate 		/*
429*0Sstevel@tonic-gate 		 * Since this routine is meant to be used to parse dhcptab
430*0Sstevel@tonic-gate 		 * symbol definitions, only a subset of the DHCP categories
431*0Sstevel@tonic-gate 		 * are valid in this context.
432*0Sstevel@tonic-gate 		 */
433*0Sstevel@tonic-gate 		if (entry->dc_dhcptab) {
434*0Sstevel@tonic-gate 			*cat = entry->dc_id;
435*0Sstevel@tonic-gate 		} else {
436*0Sstevel@tonic-gate 			ret = DSYM_INVALID_CAT;
437*0Sstevel@tonic-gate 		}
438*0Sstevel@tonic-gate 	}
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	return (ret);
441*0Sstevel@tonic-gate }
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate /*
444*0Sstevel@tonic-gate  * dsym_parse_intrange(): given a DHCP integer field, returns the value
445*0Sstevel@tonic-gate  *
446*0Sstevel@tonic-gate  *  input: const char *: a DHCP code field
447*0Sstevel@tonic-gate  *         int *: the return location for the value
448*0Sstevel@tonic-gate  *         int: the minimum valid value
449*0Sstevel@tonic-gate  *         int: the maximum valid value
450*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DSYM_SYNTAX_ERROR, or DSYM_VALUE_OUT_OF_RANGE
451*0Sstevel@tonic-gate  */
452*0Sstevel@tonic-gate static dsym_errcode_t
453*0Sstevel@tonic-gate dsym_parse_intrange(const char *field, int *intval, int min, int max)
454*0Sstevel@tonic-gate {
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	int ret;
457*0Sstevel@tonic-gate 	long longval;
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	ret = dsym_get_long(field, &longval);
460*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
461*0Sstevel@tonic-gate 		if (longval < min || longval > max) {
462*0Sstevel@tonic-gate 			ret = DSYM_VALUE_OUT_OF_RANGE;
463*0Sstevel@tonic-gate 		} else {
464*0Sstevel@tonic-gate 			*intval = (int)longval;
465*0Sstevel@tonic-gate 		}
466*0Sstevel@tonic-gate 	}
467*0Sstevel@tonic-gate 	return (ret);
468*0Sstevel@tonic-gate }
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate /*
471*0Sstevel@tonic-gate  * dsym_validate_code(): given a symbol category and code, validates
472*0Sstevel@tonic-gate  *                       that the code is valid for the category
473*0Sstevel@tonic-gate  *
474*0Sstevel@tonic-gate  *  input: dsym_category_t: the symbol category
475*0Sstevel@tonic-gate  *         uint16_t: the symbol code
476*0Sstevel@tonic-gate  * output: DSYM_SUCCESS, DSYM_INVALID_CAT or DSYM_CODE_OUT_OF_RANGE
477*0Sstevel@tonic-gate  */
478*0Sstevel@tonic-gate static dsym_errcode_t
479*0Sstevel@tonic-gate dsym_validate_code(dsym_category_t cat, ushort_t code)
480*0Sstevel@tonic-gate {
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	int cnt = sizeof (cats) / sizeof (dsym_cat_t);
483*0Sstevel@tonic-gate 	int i;
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	/*
486*0Sstevel@tonic-gate 	 * Find the category entry from the internal table.
487*0Sstevel@tonic-gate 	 */
488*0Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
489*0Sstevel@tonic-gate 		dsym_cat_t *entry;
490*0Sstevel@tonic-gate 		if (cat == cats[i].dc_id) {
491*0Sstevel@tonic-gate 			entry = &cats[i];
492*0Sstevel@tonic-gate 			if (code < entry->dc_min || code > entry->dc_max) {
493*0Sstevel@tonic-gate 				return (DSYM_CODE_OUT_OF_RANGE);
494*0Sstevel@tonic-gate 			}
495*0Sstevel@tonic-gate 			return (DSYM_SUCCESS);
496*0Sstevel@tonic-gate 		}
497*0Sstevel@tonic-gate 	}
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	return (DSYM_INVALID_CAT);
500*0Sstevel@tonic-gate }
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate /*
503*0Sstevel@tonic-gate  * dsym_validate_granularity(): given a symbol type, validates
504*0Sstevel@tonic-gate  *                       	that the granularity is valid for the type
505*0Sstevel@tonic-gate  *
506*0Sstevel@tonic-gate  *  input: dsym_cdtype_t: the symbol type
507*0Sstevel@tonic-gate  *         uchar_t: the symbol granularity
508*0Sstevel@tonic-gate  * output: DSYM_SUCCESS or DSYM_VALUE_OUT_OF_RANGE
509*0Sstevel@tonic-gate  */
510*0Sstevel@tonic-gate static dsym_errcode_t
511*0Sstevel@tonic-gate dsym_validate_granularity(dsym_cdtype_t type, uchar_t gran)
512*0Sstevel@tonic-gate {
513*0Sstevel@tonic-gate 	/*
514*0Sstevel@tonic-gate 	 * We only need to check for a 0 with non-boolean types, as
515*0Sstevel@tonic-gate 	 * anything else is already validated by the ranges passed to
516*0Sstevel@tonic-gate 	 * dsym_parse_intrange() in dsym_parse_field().
517*0Sstevel@tonic-gate 	 */
518*0Sstevel@tonic-gate 	if (gran == 0 && type != DSYM_BOOL) {
519*0Sstevel@tonic-gate 		return (DSYM_VALUE_OUT_OF_RANGE);
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate 	return (DSYM_SUCCESS);
522*0Sstevel@tonic-gate }
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate /*
525*0Sstevel@tonic-gate  * dsym_get_type_by_name(): given a type field, returns the pointer to its
526*0Sstevel@tonic-gate  *                          entry in the internal type table.
527*0Sstevel@tonic-gate  *
528*0Sstevel@tonic-gate  *  input: const char *: the type name
529*0Sstevel@tonic-gate  *         dsym_type_t *: the return location for the pointer to the table entry
530*0Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
531*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE
532*0Sstevel@tonic-gate  */
533*0Sstevel@tonic-gate static dsym_errcode_t
534*0Sstevel@tonic-gate dsym_get_type_by_name(const char *type, dsym_type_t **entry, boolean_t cs)
535*0Sstevel@tonic-gate {
536*0Sstevel@tonic-gate 	int cnt = sizeof (types) / sizeof (dsym_type_t);
537*0Sstevel@tonic-gate 	int result;
538*0Sstevel@tonic-gate 	int i;
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 		if (cs) {
543*0Sstevel@tonic-gate 			result = strcmp(type, types[i].dt_string);
544*0Sstevel@tonic-gate 		} else {
545*0Sstevel@tonic-gate 			result = strcasecmp(type, types[i].dt_string);
546*0Sstevel@tonic-gate 		}
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 		if (result == 0) {
549*0Sstevel@tonic-gate 			*entry = &types[i];
550*0Sstevel@tonic-gate 			return (DSYM_SUCCESS);
551*0Sstevel@tonic-gate 		}
552*0Sstevel@tonic-gate 	}
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 	return (DSYM_INVALID_TYPE);
555*0Sstevel@tonic-gate }
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate /*
558*0Sstevel@tonic-gate  * dsym_parse_type(): given a DHCP type string, returns the type id
559*0Sstevel@tonic-gate  *
560*0Sstevel@tonic-gate  *  input: char *: a DHCP type string
561*0Sstevel@tonic-gate  *         dsym_cdtype_t *: the return location for the type id
562*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE
563*0Sstevel@tonic-gate  */
564*0Sstevel@tonic-gate static dsym_errcode_t
565*0Sstevel@tonic-gate dsym_parse_type(char *field, dsym_cdtype_t *type)
566*0Sstevel@tonic-gate {
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	dsym_type_t *entry;
569*0Sstevel@tonic-gate 	int ret;
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	ret = dsym_get_type_by_name(field, &entry, B_TRUE);
572*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
573*0Sstevel@tonic-gate 		/*
574*0Sstevel@tonic-gate 		 * Since this routine is meant to be used to parse dhcptab
575*0Sstevel@tonic-gate 		 * symbol definitions, only a subset of the DHCP type
576*0Sstevel@tonic-gate 		 * are valid in this context.
577*0Sstevel@tonic-gate 		 */
578*0Sstevel@tonic-gate 		if (entry->dt_dhcptab) {
579*0Sstevel@tonic-gate 			*type = entry->dt_id;
580*0Sstevel@tonic-gate 		} else {
581*0Sstevel@tonic-gate 			ret = DSYM_INVALID_TYPE;
582*0Sstevel@tonic-gate 		}
583*0Sstevel@tonic-gate 	}
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	return (ret);
586*0Sstevel@tonic-gate }
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate /*
589*0Sstevel@tonic-gate  * dsym_free_fields(): frees an array of fields allocated by
590*0Sstevel@tonic-gate  *                     dsym_init_parser().
591*0Sstevel@tonic-gate  *
592*0Sstevel@tonic-gate  *  input: char **: array of fields to free
593*0Sstevel@tonic-gate  * output: none
594*0Sstevel@tonic-gate  */
595*0Sstevel@tonic-gate void
596*0Sstevel@tonic-gate dsym_free_fields(char **fields)
597*0Sstevel@tonic-gate {
598*0Sstevel@tonic-gate 	int i;
599*0Sstevel@tonic-gate 	if (fields != NULL) {
600*0Sstevel@tonic-gate 		for (i = 0; i < DSYM_NUM_FIELDS; i++) {
601*0Sstevel@tonic-gate 			free(fields[i]);
602*0Sstevel@tonic-gate 		}
603*0Sstevel@tonic-gate 		free(fields);
604*0Sstevel@tonic-gate 	}
605*0Sstevel@tonic-gate }
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate /*
608*0Sstevel@tonic-gate  * dsym_close_parser(): free up all resources associated with the parser
609*0Sstevel@tonic-gate  *
610*0Sstevel@tonic-gate  *  input: char **: the fields allocated by dsym_init_parser()
611*0Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure populated by dsym_init_parser()
612*0Sstevel@tonic-gate  * output: none
613*0Sstevel@tonic-gate  */
614*0Sstevel@tonic-gate void
615*0Sstevel@tonic-gate dsym_close_parser(char **fields, dhcp_symbol_t *sym)
616*0Sstevel@tonic-gate {
617*0Sstevel@tonic-gate 	dsym_free_fields(fields);
618*0Sstevel@tonic-gate 	dsym_free_classes(&sym->ds_classes);
619*0Sstevel@tonic-gate }
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate /*
622*0Sstevel@tonic-gate  * dsym_init_parser(): initializes the structures used to parse a symbol
623*0Sstevel@tonic-gate  *                     value.
624*0Sstevel@tonic-gate  *
625*0Sstevel@tonic-gate  *  input: const char *: the symbol name
626*0Sstevel@tonic-gate  *         const char *: the symbol value in dhcptab format
627*0Sstevel@tonic-gate  *         char ***: the return location for the symbol fields
628*0Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure which eventually will
629*0Sstevel@tonic-gate  *                          be the repository for the parsed symbol data
630*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DYSM_NO_MEMORY, DSYM_NULL_FIELD or
631*0Sstevel@tonic-gate  *              DSYM_TOO_MANY_FIELDS
632*0Sstevel@tonic-gate  */
633*0Sstevel@tonic-gate dsym_errcode_t
634*0Sstevel@tonic-gate dsym_init_parser(const char *name, const char *value, char ***fields_ret,
635*0Sstevel@tonic-gate     dhcp_symbol_t *sym)
636*0Sstevel@tonic-gate {
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
639*0Sstevel@tonic-gate 	char *cp;
640*0Sstevel@tonic-gate 	char *next;
641*0Sstevel@tonic-gate 	char *field;
642*0Sstevel@tonic-gate 	char **fields;
643*0Sstevel@tonic-gate 	int i;
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	/*
646*0Sstevel@tonic-gate 	 * Initialize the symbol structure.
647*0Sstevel@tonic-gate 	 */
648*0Sstevel@tonic-gate 	sym->ds_category = 0;
649*0Sstevel@tonic-gate 	sym->ds_code = 0;
650*0Sstevel@tonic-gate 	(void) strlcpy(sym->ds_name, name, DSYM_MAX_SYM_LEN);
651*0Sstevel@tonic-gate 	sym->ds_type = 0;
652*0Sstevel@tonic-gate 	sym->ds_gran = 0;
653*0Sstevel@tonic-gate 	sym->ds_max = 0;
654*0Sstevel@tonic-gate 	sym->ds_classes.dc_names = NULL;
655*0Sstevel@tonic-gate 	sym->ds_classes.dc_cnt = 0;
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	if ((cp = strdup(value)) == NULL ||
658*0Sstevel@tonic-gate 	    (fields = calloc(DSYM_NUM_FIELDS, sizeof (char *))) == NULL) {
659*0Sstevel@tonic-gate 		ret = DSYM_NO_MEMORY;
660*0Sstevel@tonic-gate 	}
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	next = cp;
663*0Sstevel@tonic-gate 	for (i = 0; ret == DSYM_SUCCESS && i < DSYM_NUM_FIELDS; i++) {
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 		field = dsym_get_token(next, DSYM_FIELD_DEL, &next,
666*0Sstevel@tonic-gate 			B_FALSE);
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 		if (field == NULL) {
669*0Sstevel@tonic-gate 			ret = DSYM_NULL_FIELD;
670*0Sstevel@tonic-gate 			continue;
671*0Sstevel@tonic-gate 		}
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 		dsym_trim(&field);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 		if (strlen(field) == 0) {
676*0Sstevel@tonic-gate 			ret = DSYM_NULL_FIELD;
677*0Sstevel@tonic-gate 			continue;
678*0Sstevel@tonic-gate 		}
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 		if ((fields[i] = strdup(field)) == NULL) {
681*0Sstevel@tonic-gate 			ret = DSYM_NO_MEMORY;
682*0Sstevel@tonic-gate 			continue;
683*0Sstevel@tonic-gate 		}
684*0Sstevel@tonic-gate 	}
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS &&
687*0Sstevel@tonic-gate 	    dsym_get_token(next, DSYM_FIELD_DEL, &next, B_FALSE) != NULL) {
688*0Sstevel@tonic-gate 		ret = DSYM_TOO_MANY_FIELDS;
689*0Sstevel@tonic-gate 	}
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 	if (ret != DSYM_SUCCESS) {
692*0Sstevel@tonic-gate 		dsym_free_fields(fields);
693*0Sstevel@tonic-gate 	} else {
694*0Sstevel@tonic-gate 		*fields_ret = fields;
695*0Sstevel@tonic-gate 	}
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	free(cp);
698*0Sstevel@tonic-gate 	return (ret);
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate /*
702*0Sstevel@tonic-gate  * dsym_parse_field(): parses the specified symbol field.
703*0Sstevel@tonic-gate  *
704*0Sstevel@tonic-gate  *  input: int: the field number to be parsed.
705*0Sstevel@tonic-gate  *         char **: symbol fields initialized by dsym_init_parser()
706*0Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure which will be the repository
707*0Sstevel@tonic-gate  *                          for the parsed field
708*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DSYM_SYNTAX_ERROR, DSYM_CODE_OUT_OF_RANGE,
709*0Sstevel@tonic-gate  *              DSYM_INVALID_CAT, DSYM_INVALID_TYPE, DSYM_EXCEEDS_CLASS_SIZE,
710*0Sstevel@tonic-gate  *              DSYM_EXCEEDS_MAX_CLASS_SIZE, DSYM_NO_MEMORY,
711*0Sstevel@tonic-gate  *              DSYM_INVALID_FIELD_NUM, DSYM_VALUE_OUT_OF_RANGE
712*0Sstevel@tonic-gate  */
713*0Sstevel@tonic-gate dsym_errcode_t
714*0Sstevel@tonic-gate dsym_parse_field(int field_num, char **fields, dhcp_symbol_t *sym)
715*0Sstevel@tonic-gate {
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	int 	ret = DSYM_SUCCESS;
718*0Sstevel@tonic-gate 	int	intval;
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	switch (field_num) {
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	case DSYM_CAT_FIELD:
723*0Sstevel@tonic-gate 		ret = dsym_parse_cat(fields[field_num], &sym->ds_category);
724*0Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS && sym->ds_category == DSYM_VENDOR) {
725*0Sstevel@tonic-gate 			ret = dsym_parse_classes(fields[field_num],
726*0Sstevel@tonic-gate 			    &sym->ds_classes);
727*0Sstevel@tonic-gate 		}
728*0Sstevel@tonic-gate 		break;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	case DSYM_CODE_FIELD:
731*0Sstevel@tonic-gate 		ret = dsym_parse_intrange(fields[field_num], &intval, 0,
732*0Sstevel@tonic-gate 		    USHRT_MAX);
733*0Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS) {
734*0Sstevel@tonic-gate 			sym->ds_code = (ushort_t)intval;
735*0Sstevel@tonic-gate 			ret = dsym_validate_code(sym->ds_category,
736*0Sstevel@tonic-gate 			    sym->ds_code);
737*0Sstevel@tonic-gate 		}
738*0Sstevel@tonic-gate 		break;
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	case DSYM_TYPE_FIELD:
741*0Sstevel@tonic-gate 		ret = dsym_parse_type(fields[field_num], &sym->ds_type);
742*0Sstevel@tonic-gate 		break;
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	case DSYM_GRAN_FIELD:
745*0Sstevel@tonic-gate 		ret = dsym_parse_intrange(fields[field_num], &intval, 0,
746*0Sstevel@tonic-gate 		    UCHAR_MAX);
747*0Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS) {
748*0Sstevel@tonic-gate 			sym->ds_gran = (uchar_t)intval;
749*0Sstevel@tonic-gate 			ret = dsym_validate_granularity(sym->ds_type,
750*0Sstevel@tonic-gate 			    sym->ds_gran);
751*0Sstevel@tonic-gate 		}
752*0Sstevel@tonic-gate 		break;
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	case DSYM_MAX_FIELD:
755*0Sstevel@tonic-gate 		ret = dsym_parse_intrange(fields[field_num], &intval, 0,
756*0Sstevel@tonic-gate 		    UCHAR_MAX);
757*0Sstevel@tonic-gate 		if (ret == DSYM_SUCCESS) {
758*0Sstevel@tonic-gate 			sym->ds_max = (uchar_t)intval;
759*0Sstevel@tonic-gate 		}
760*0Sstevel@tonic-gate 		break;
761*0Sstevel@tonic-gate 	default:
762*0Sstevel@tonic-gate 		ret = DSYM_INVALID_FIELD_NUM;
763*0Sstevel@tonic-gate 	}
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	return (ret);
766*0Sstevel@tonic-gate }
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate /*
769*0Sstevel@tonic-gate  * dsym_parser(): parses a DHCP symbol value
770*0Sstevel@tonic-gate  *
771*0Sstevel@tonic-gate  *  input: char **: symbol fields initialized by dsym_init_parser()
772*0Sstevel@tonic-gate  *         dhcp_symbol_t *: the structure which will be the repository
773*0Sstevel@tonic-gate  *                          for the parsed field
774*0Sstevel@tonic-gate  *         int *: last field processed
775*0Sstevel@tonic-gate  *         boolean_t: parse all fields even though errors occur?
776*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS, DSYM_SYNTAX_ERROR, DSYM_CODE_OUT_OF_RANGE,
777*0Sstevel@tonic-gate  *              DSYM_INVALID_CAT, DSYM_INVALID_TYPE, DSYM_EXCEEDS_CLASS_SIZE,
778*0Sstevel@tonic-gate  *              DSYM_EXCEEDS_MAX_CLASS_SIZE, DSYM_NO_MEMORY
779*0Sstevel@tonic-gate  *              DSYM_INVALID_FIELD_NUM, DSYM_VALUE_OUT_OF_RANGE
780*0Sstevel@tonic-gate  */
781*0Sstevel@tonic-gate dsym_errcode_t
782*0Sstevel@tonic-gate dsym_parser(char **fields, dhcp_symbol_t *sym, int *lastField,
783*0Sstevel@tonic-gate     boolean_t bestEffort)
784*0Sstevel@tonic-gate {
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	int ret = DSYM_SUCCESS;
787*0Sstevel@tonic-gate 	int tret = DSYM_SUCCESS;
788*0Sstevel@tonic-gate 	int i;
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate 	*lastField = -1;
791*0Sstevel@tonic-gate 	for (i = DSYM_FIRST_FIELD;
792*0Sstevel@tonic-gate 	    tret == DSYM_SUCCESS && i < DSYM_NUM_FIELDS; i++) {
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 		tret = dsym_parse_field(i, fields, sym);
795*0Sstevel@tonic-gate 		if (tret != DSYM_SUCCESS) {
796*0Sstevel@tonic-gate 			if (ret == DSYM_SUCCESS) {
797*0Sstevel@tonic-gate 				ret = tret;
798*0Sstevel@tonic-gate 			}
799*0Sstevel@tonic-gate 			if (bestEffort) {
800*0Sstevel@tonic-gate 				*lastField = i;
801*0Sstevel@tonic-gate 				tret = DSYM_SUCCESS;
802*0Sstevel@tonic-gate 			}
803*0Sstevel@tonic-gate 		}
804*0Sstevel@tonic-gate 	}
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	if (*lastField == -1) {
807*0Sstevel@tonic-gate 		*lastField = i - 1;
808*0Sstevel@tonic-gate 	}
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 	return (ret);
811*0Sstevel@tonic-gate }
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate /*
814*0Sstevel@tonic-gate  * dsym_get_cat_id(): given a category string, return the associated id.
815*0Sstevel@tonic-gate  *
816*0Sstevel@tonic-gate  *  input: const char *: the category name
817*0Sstevel@tonic-gate  *         dsym_category_t *: the return location for the id
818*0Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
819*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
820*0Sstevel@tonic-gate  */
821*0Sstevel@tonic-gate dsym_errcode_t
822*0Sstevel@tonic-gate dsym_get_cat_id(const char *cat, dsym_category_t *id, boolean_t cs)
823*0Sstevel@tonic-gate {
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	dsym_cat_t *entry;
826*0Sstevel@tonic-gate 	int ret;
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 	ret = dsym_get_cat_by_name(cat, &entry, cs);
829*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
830*0Sstevel@tonic-gate 		*id = entry->dc_id;
831*0Sstevel@tonic-gate 	}
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	return (ret);
834*0Sstevel@tonic-gate }
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate /*
837*0Sstevel@tonic-gate  * dsym_get_code_ranges(): given a category field, returns its valid code
838*0Sstevel@tonic-gate  *                         ranges.
839*0Sstevel@tonic-gate  *
840*0Sstevel@tonic-gate  *  input: const char *: the category name
841*0Sstevel@tonic-gate  *         ushort *: return location for the minimum code value.
842*0Sstevel@tonic-gate  *         ushort *: return location for the maximum code value.
843*0Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
844*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_CAT
845*0Sstevel@tonic-gate  */
846*0Sstevel@tonic-gate dsym_errcode_t
847*0Sstevel@tonic-gate dsym_get_code_ranges(const char *cat, ushort_t *min, ushort_t *max,
848*0Sstevel@tonic-gate     boolean_t cs)
849*0Sstevel@tonic-gate {
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate 	dsym_cat_t *entry;
852*0Sstevel@tonic-gate 	int ret;
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate 	ret = dsym_get_cat_by_name(cat, &entry, cs);
855*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
856*0Sstevel@tonic-gate 		*min = entry->dc_min;
857*0Sstevel@tonic-gate 		*max = entry->dc_max;
858*0Sstevel@tonic-gate 	}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	return (ret);
861*0Sstevel@tonic-gate }
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate /*
864*0Sstevel@tonic-gate  * dsym_get_type_id(): given a type string, return the associated type id.
865*0Sstevel@tonic-gate  *
866*0Sstevel@tonic-gate  *  input: const char *: the type name
867*0Sstevel@tonic-gate  *         dsym_cdtype_t *: the return location for the id
868*0Sstevel@tonic-gate  *         boolean_t: case-sensitive name compare
869*0Sstevel@tonic-gate  * output: int: DSYM_SUCCESS or DSYM_INVALID_TYPE
870*0Sstevel@tonic-gate  */
871*0Sstevel@tonic-gate dsym_errcode_t
872*0Sstevel@tonic-gate dsym_get_type_id(const char *type, dsym_cdtype_t *id, boolean_t cs)
873*0Sstevel@tonic-gate {
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	dsym_type_t *entry;
876*0Sstevel@tonic-gate 	int ret;
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	ret = dsym_get_type_by_name(type, &entry, cs);
879*0Sstevel@tonic-gate 	if (ret == DSYM_SUCCESS) {
880*0Sstevel@tonic-gate 		*id = entry->dt_id;
881*0Sstevel@tonic-gate 	}
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	return (ret);
884*0Sstevel@tonic-gate }
885