xref: /illumos-gate/usr/src/lib/fm/libdiagcode/common/diagcode.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * diagcode library, Sun Private API (PSARC/2004/601)
29*7c478bd9Sstevel@tonic-gate  *
30*7c478bd9Sstevel@tonic-gate  * undocumented debugging interface:
31*7c478bd9Sstevel@tonic-gate  *	set environment variable _FM_DC_DEBUG for debug prints to stderr.
32*7c478bd9Sstevel@tonic-gate  *	set it to 1 for extended error messages only.
33*7c478bd9Sstevel@tonic-gate  *	set it to 2 to include success info too on interesting functions.
34*7c478bd9Sstevel@tonic-gate  *	set it to 3 to include success info on trivial functions too.
35*7c478bd9Sstevel@tonic-gate  * note that this environment variable is only examined in fm_dc_opendict().
36*7c478bd9Sstevel@tonic-gate  */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <stdio.h>
39*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
40*7c478bd9Sstevel@tonic-gate #include <string.h>
41*7c478bd9Sstevel@tonic-gate #include <ctype.h>
42*7c478bd9Sstevel@tonic-gate #include <alloca.h>
43*7c478bd9Sstevel@tonic-gate #include <errno.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #include <fm/diagcode.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /* private (opaque to callers) handle information */
48*7c478bd9Sstevel@tonic-gate struct fm_dc_handle {
49*7c478bd9Sstevel@tonic-gate 	const char *dictname;
50*7c478bd9Sstevel@tonic-gate 	FILE *fp;
51*7c478bd9Sstevel@tonic-gate 	unsigned maxkey;
52*7c478bd9Sstevel@tonic-gate 	int version;
53*7c478bd9Sstevel@tonic-gate 	int debug;
54*7c478bd9Sstevel@tonic-gate 	/* name/value pairs from .dict header */
55*7c478bd9Sstevel@tonic-gate 	struct fm_dc_prop {
56*7c478bd9Sstevel@tonic-gate 		struct fm_dc_prop *next;
57*7c478bd9Sstevel@tonic-gate 		const char *lhs;
58*7c478bd9Sstevel@tonic-gate 		const char *rhs;
59*7c478bd9Sstevel@tonic-gate 	} *props;
60*7c478bd9Sstevel@tonic-gate };
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /*
63*7c478bd9Sstevel@tonic-gate  * parameters of the various sizes of diagcodes
64*7c478bd9Sstevel@tonic-gate  *
65*7c478bd9Sstevel@tonic-gate  * table must be in ascending order from smallest databits value to largest.
66*7c478bd9Sstevel@tonic-gate  * when faced with more databits than the last entry, we know we have
67*7c478bd9Sstevel@tonic-gate  * something that won't fit into a diagcode.
68*7c478bd9Sstevel@tonic-gate  */
69*7c478bd9Sstevel@tonic-gate static const struct info {
70*7c478bd9Sstevel@tonic-gate 	int databits;	/* number of bits used to hold dictionary value */
71*7c478bd9Sstevel@tonic-gate 	int numx;	/* number of digits (also called X's) in code */
72*7c478bd9Sstevel@tonic-gate 	int csumbits;	/* number of bits used for checksum */
73*7c478bd9Sstevel@tonic-gate 	int sizeval;	/* value encoded into "size" field of code */
74*7c478bd9Sstevel@tonic-gate 	unsigned long long offset;	/* databits==0 stands for this value */
75*7c478bd9Sstevel@tonic-gate } Info[] = {
76*7c478bd9Sstevel@tonic-gate 	/*  diagcode is: dictname-XXXX-XX */
77*7c478bd9Sstevel@tonic-gate 	{ 21, 6, 5, 0, 0ULL },
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	/*  diagcode is: dictname-XXXX-XXXX-XX */
80*7c478bd9Sstevel@tonic-gate 	{ 38, 10, 8, 1, 2097152ULL },
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	/*  diagcode is: dictname-XXXX-XXXX-XXXX-XX */
83*7c478bd9Sstevel@tonic-gate 	{ 55, 14, 11, 2, 274880004096ULL },
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	/*  diagcode is: dictname-XXXX-XXXX-XXXX-XXXX-XX */
86*7c478bd9Sstevel@tonic-gate 	{ 72, 18, 14, 3, 36029071898968064ULL }
87*7c478bd9Sstevel@tonic-gate };
88*7c478bd9Sstevel@tonic-gate #define	MAXDATABITS 72	/* highest entry in table above */
89*7c478bd9Sstevel@tonic-gate #define	MAXCODELEN 25	/* big enough to hold the X's, dashes, and \0 */
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate /* forward references for functions private to this file */
92*7c478bd9Sstevel@tonic-gate typedef struct bitv bitv;
93*7c478bd9Sstevel@tonic-gate static const struct info *dictval2info(const bitv *bv);
94*7c478bd9Sstevel@tonic-gate static const struct info *numx2info(int numx);
95*7c478bd9Sstevel@tonic-gate static void sortkey(const char *key[]);
96*7c478bd9Sstevel@tonic-gate static const char *keymatch(const char *linebuf, const char *key[]);
97*7c478bd9Sstevel@tonic-gate static int buildcode(fm_dc_handle_t *dhp, const char *rhsp,
98*7c478bd9Sstevel@tonic-gate     char *code, size_t maxcode, char *debugstr);
99*7c478bd9Sstevel@tonic-gate static bitv *code2dictval(fm_dc_handle_t *dhp, const char *code);
100*7c478bd9Sstevel@tonic-gate struct parsestate {
101*7c478bd9Sstevel@tonic-gate 	char *parseptr;	/* next unparsed character in buffer */
102*7c478bd9Sstevel@tonic-gate 	char *rhsp;	/* rhs associated with last lhs (or NULL) */
103*7c478bd9Sstevel@tonic-gate };
104*7c478bd9Sstevel@tonic-gate static void startparse(struct parsestate *ps, char *ptr);
105*7c478bd9Sstevel@tonic-gate static char *nextlhs(struct parsestate *ps);
106*7c478bd9Sstevel@tonic-gate static char *nextrhs(struct parsestate *ps);
107*7c478bd9Sstevel@tonic-gate static bitv *bitv_alloc(void);
108*7c478bd9Sstevel@tonic-gate static void bitv_free(bitv *bv);
109*7c478bd9Sstevel@tonic-gate static void bitv_shift(bitv *bv, unsigned bits);
110*7c478bd9Sstevel@tonic-gate static void bitv_setlo(bitv *bv, unsigned bits, unsigned val);
111*7c478bd9Sstevel@tonic-gate static void bitv_shiftin(bitv *bv, unsigned bits, unsigned val);
112*7c478bd9Sstevel@tonic-gate static void bitv_shiftinv(bitv *bv, unsigned bits, const bitv *inbv);
113*7c478bd9Sstevel@tonic-gate static int bitv_bits(const bitv *bv);
114*7c478bd9Sstevel@tonic-gate static unsigned bitv_chunk(const bitv *bv, unsigned limbit, unsigned lobit);
115*7c478bd9Sstevel@tonic-gate static int bitv_mul(bitv *bv, unsigned long long val);
116*7c478bd9Sstevel@tonic-gate static int bitv_add(bitv *bv, unsigned long long val);
117*7c478bd9Sstevel@tonic-gate static int bitv_sub(bitv *bv, unsigned long long val);
118*7c478bd9Sstevel@tonic-gate static int bitv_ge(const bitv *bv, unsigned long long val);
119*7c478bd9Sstevel@tonic-gate static bitv *bitv_strparse(const char *s, int bits);
120*7c478bd9Sstevel@tonic-gate static int bitv_cmp(const bitv *bv1, const bitv *bv2);
121*7c478bd9Sstevel@tonic-gate static void crc(unsigned long *crcp, unsigned val);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate #define	DICTMAXLINE	10240	/* maximum expected dictionary line length */
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate #define	MAXDEBUGSTR	100	/* for debug messages */
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate static const char Suffix[] = ".dict";	/* suffix on dictionary filename */
128*7c478bd9Sstevel@tonic-gate static const char Defaultpath[] = "/usr/lib/fm/dict";
129*7c478bd9Sstevel@tonic-gate static const char Debugenv[] = "_FM_DC_DEBUG";	/* debug environment var */
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate /* properties we look for at top of dictionary */
132*7c478bd9Sstevel@tonic-gate static const char Header[] = "FMDICT: ";
133*7c478bd9Sstevel@tonic-gate static const char Name[] = "name";
134*7c478bd9Sstevel@tonic-gate static const char Version[] = "version";
135*7c478bd9Sstevel@tonic-gate static const char Maxkey[] = "maxkey";
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate /* the alphabet used to encode information in a diagcode (base32 digits) */
138*7c478bd9Sstevel@tonic-gate static const char Alphabet[] = "0123456789ACDEFGHJKLMNPQRSTUVWXY";
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /* open a dictionary, return opaque handle */
141*7c478bd9Sstevel@tonic-gate fm_dc_handle_t *
fm_dc_opendict(int version,const char * dirpath,const char * dictname)142*7c478bd9Sstevel@tonic-gate fm_dc_opendict(int version, const char *dirpath, const char *dictname)
143*7c478bd9Sstevel@tonic-gate {
144*7c478bd9Sstevel@tonic-gate 	int debug = 0;			/* set by environment variable */
145*7c478bd9Sstevel@tonic-gate 	char *debugstr = "";		/* error path debug prefix text */
146*7c478bd9Sstevel@tonic-gate 	fm_dc_handle_t *dhp = NULL;
147*7c478bd9Sstevel@tonic-gate 	char *fname;			/* full dict file name */
148*7c478bd9Sstevel@tonic-gate 	char linebuf[DICTMAXLINE];	/* line read from dict */
149*7c478bd9Sstevel@tonic-gate 	int line = 0;			/* line number in dict */
150*7c478bd9Sstevel@tonic-gate 	unsigned prop_version = 0;	/* version property from dict */
151*7c478bd9Sstevel@tonic-gate 	char *prop_name = "";		/* name property from dict */
152*7c478bd9Sstevel@tonic-gate 	char *lhsp;			/* prop left-hand-side */
153*7c478bd9Sstevel@tonic-gate 	char *rhsp;			/* prop right-hand-side */
154*7c478bd9Sstevel@tonic-gate 	struct parsestate pstate;	/* for startparse(), nextlhs(), etc */
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	/* undocumented flag, given via environment variable */
157*7c478bd9Sstevel@tonic-gate 	if ((rhsp = getenv(Debugenv)) != NULL)
158*7c478bd9Sstevel@tonic-gate 		debug = atoi(rhsp);
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	if (debug > 1)
161*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
162*7c478bd9Sstevel@tonic-gate 		    "fm_dc_opendict: ver %d path \"%s\" dict \"%s\": ",
163*7c478bd9Sstevel@tonic-gate 		    version, (dirpath == NULL) ? "NULL" : dirpath, dictname);
164*7c478bd9Sstevel@tonic-gate 	else if (debug)
165*7c478bd9Sstevel@tonic-gate 		debugstr = "fm_dc_opendict: ";	/* used in error paths */
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	/* verify caller expects an API version we support */
168*7c478bd9Sstevel@tonic-gate 	if (version < 0 || version > FM_DC_VERSION) {
169*7c478bd9Sstevel@tonic-gate 		if (debug)
170*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%sENOTSUP ver not in [0-%d]\n",
171*7c478bd9Sstevel@tonic-gate 			    debugstr, FM_DC_VERSION);
172*7c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
173*7c478bd9Sstevel@tonic-gate 		return (NULL);
174*7c478bd9Sstevel@tonic-gate 	}
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	/* caller can pass in NULL for default dirpath */
177*7c478bd9Sstevel@tonic-gate 	if (dirpath == NULL)
178*7c478bd9Sstevel@tonic-gate 		dirpath = Defaultpath;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	/*
181*7c478bd9Sstevel@tonic-gate 	 * allocate buffer for dirpath, slash, dictname, and suffix
182*7c478bd9Sstevel@tonic-gate 	 * (sizeof (Suffix) includes the null).
183*7c478bd9Sstevel@tonic-gate 	 */
184*7c478bd9Sstevel@tonic-gate 	fname = alloca(strlen(dirpath) + 1 +
185*7c478bd9Sstevel@tonic-gate 	    strlen(dictname) + sizeof (Suffix));
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	/*
188*7c478bd9Sstevel@tonic-gate 	 * allocate the handle.
189*7c478bd9Sstevel@tonic-gate 	 *
190*7c478bd9Sstevel@tonic-gate 	 * allocate the dictname copy kept in the handle.
191*7c478bd9Sstevel@tonic-gate 	 *
192*7c478bd9Sstevel@tonic-gate 	 * if any of these fail, send back ENOMEM.
193*7c478bd9Sstevel@tonic-gate 	 */
194*7c478bd9Sstevel@tonic-gate 	if ((dhp = malloc(sizeof (*dhp))) == NULL ||
195*7c478bd9Sstevel@tonic-gate 	    (dhp->dictname = strdup(dictname)) == NULL) {
196*7c478bd9Sstevel@tonic-gate 		if (dhp)
197*7c478bd9Sstevel@tonic-gate 			free(dhp);
198*7c478bd9Sstevel@tonic-gate 		if (debug)
199*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%sENOMEM\n", debugstr);
200*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
201*7c478bd9Sstevel@tonic-gate 		return (NULL);
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	/* initialize the handle */
205*7c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, dirpath);
206*7c478bd9Sstevel@tonic-gate 	(void) strcat(fname, "/");
207*7c478bd9Sstevel@tonic-gate 	(void) strcat(fname, dictname);
208*7c478bd9Sstevel@tonic-gate 	(void) strcat(fname, Suffix);
209*7c478bd9Sstevel@tonic-gate 	dhp->fp = NULL;
210*7c478bd9Sstevel@tonic-gate 	dhp->maxkey = 0;
211*7c478bd9Sstevel@tonic-gate 	dhp->version = version;
212*7c478bd9Sstevel@tonic-gate 	dhp->debug = debug;
213*7c478bd9Sstevel@tonic-gate 	dhp->props = NULL;
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	/* open the dictionary */
216*7c478bd9Sstevel@tonic-gate 	if (debug > 1)
217*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\"%s\": ", fname);
218*7c478bd9Sstevel@tonic-gate 	if ((dhp->fp = fopen(fname, "r")) == NULL) {
219*7c478bd9Sstevel@tonic-gate 		int oerrno = errno;	/* fopen() set errno to something */
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 		if (debug > 1)
222*7c478bd9Sstevel@tonic-gate 			perror("fopen");
223*7c478bd9Sstevel@tonic-gate 		else if (debug) {
224*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s%s: ", debugstr, fname);
225*7c478bd9Sstevel@tonic-gate 			errno = oerrno;
226*7c478bd9Sstevel@tonic-gate 			perror("fopen");
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 		fm_dc_closedict(dhp);
229*7c478bd9Sstevel@tonic-gate 		errno = oerrno;
230*7c478bd9Sstevel@tonic-gate 		return (NULL);
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	/* pull in the header line and parse it */
234*7c478bd9Sstevel@tonic-gate 	while (fgets(linebuf, DICTMAXLINE, dhp->fp) != NULL) {
235*7c478bd9Sstevel@tonic-gate 		line++;
236*7c478bd9Sstevel@tonic-gate 		if (*linebuf == '\n' || *linebuf == '#')
237*7c478bd9Sstevel@tonic-gate 			continue;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 		/* first non-comment, non-blank line must be header */
240*7c478bd9Sstevel@tonic-gate 		if (strncmp(linebuf, Header, sizeof (Header) - 1)) {
241*7c478bd9Sstevel@tonic-gate 			fm_dc_closedict(dhp);
242*7c478bd9Sstevel@tonic-gate 			if (debug)
243*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
244*7c478bd9Sstevel@tonic-gate 				    "%sEINVAL: line %d: header expected.\n",
245*7c478bd9Sstevel@tonic-gate 				    debugstr, line);
246*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
247*7c478bd9Sstevel@tonic-gate 			return (NULL);
248*7c478bd9Sstevel@tonic-gate 		}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 		/* just wanted header line for now */
251*7c478bd9Sstevel@tonic-gate 		break;
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	/* walk through name=value pairs in line after Header string */
255*7c478bd9Sstevel@tonic-gate 	startparse(&pstate, &linebuf[sizeof (Header) - 1]);
256*7c478bd9Sstevel@tonic-gate 	while ((lhsp = nextlhs(&pstate)) != NULL) {
257*7c478bd9Sstevel@tonic-gate 		struct fm_dc_prop *propp;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 		if ((rhsp = nextrhs(&pstate)) == NULL) {
260*7c478bd9Sstevel@tonic-gate 			if (debug)
261*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%sEINVAL "
262*7c478bd9Sstevel@tonic-gate 				    "%s prop has no value\n", debugstr, lhsp);
263*7c478bd9Sstevel@tonic-gate 			fm_dc_closedict(dhp);
264*7c478bd9Sstevel@tonic-gate 			errno = EINVAL;
265*7c478bd9Sstevel@tonic-gate 			return (NULL);
266*7c478bd9Sstevel@tonic-gate 		}
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 		propp = malloc(sizeof (*propp));
269*7c478bd9Sstevel@tonic-gate 		if (propp == NULL ||
270*7c478bd9Sstevel@tonic-gate 		    (propp->lhs = strdup(lhsp)) == NULL ||
271*7c478bd9Sstevel@tonic-gate 		    (propp->rhs = strdup(rhsp)) == NULL) {
272*7c478bd9Sstevel@tonic-gate 			if (debug)
273*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%sENOMEM\n", debugstr);
274*7c478bd9Sstevel@tonic-gate 			if (propp != NULL) {
275*7c478bd9Sstevel@tonic-gate 				if (propp->lhs != NULL)
276*7c478bd9Sstevel@tonic-gate 					free((void *) propp->lhs);
277*7c478bd9Sstevel@tonic-gate 				free((void *) propp);
278*7c478bd9Sstevel@tonic-gate 			}
279*7c478bd9Sstevel@tonic-gate 			fm_dc_closedict(dhp);
280*7c478bd9Sstevel@tonic-gate 			errno = ENOMEM;
281*7c478bd9Sstevel@tonic-gate 			return (NULL);
282*7c478bd9Sstevel@tonic-gate 		}
283*7c478bd9Sstevel@tonic-gate 		propp->next = dhp->props;
284*7c478bd9Sstevel@tonic-gate 		dhp->props = propp;
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 		if (strcmp(lhsp, Name) == 0)
287*7c478bd9Sstevel@tonic-gate 			prop_name = rhsp;
288*7c478bd9Sstevel@tonic-gate 		else if (strcmp(lhsp, Version) == 0)
289*7c478bd9Sstevel@tonic-gate 			prop_version = strtoul(rhsp, NULL, 0);
290*7c478bd9Sstevel@tonic-gate 		else if (strcmp(lhsp, Maxkey) == 0)
291*7c478bd9Sstevel@tonic-gate 			dhp->maxkey = strtoul(rhsp, NULL, 0);
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	/*
295*7c478bd9Sstevel@tonic-gate 	 * require version 1, expected dict name, and maxkey values
296*7c478bd9Sstevel@tonic-gate 	 * (note we use "1" here and not FM_DC_VERSION because this code
297*7c478bd9Sstevel@tonic-gate 	 * implements version 1, so the check below should not float to
298*7c478bd9Sstevel@tonic-gate 	 * newer version numbers if the header file defines them.)
299*7c478bd9Sstevel@tonic-gate 	 */
300*7c478bd9Sstevel@tonic-gate 	if (prop_version != 1UL || strcmp(prop_name, dictname) ||
301*7c478bd9Sstevel@tonic-gate 	    dhp->maxkey == 0) {
302*7c478bd9Sstevel@tonic-gate 		fm_dc_closedict(dhp);
303*7c478bd9Sstevel@tonic-gate 		if (debug)
304*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
305*7c478bd9Sstevel@tonic-gate 			    "%sEINVAL ver %d name \"%s\" maxkey %d\n",
306*7c478bd9Sstevel@tonic-gate 			    debugstr, prop_version, prop_name, dhp->maxkey);
307*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
308*7c478bd9Sstevel@tonic-gate 		return (NULL);
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	if (debug > 1)
312*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "fm_dc_opendict: dhp 0x%p\n",
313*7c478bd9Sstevel@tonic-gate 		    (void *)dhp);
314*7c478bd9Sstevel@tonic-gate 	return (dhp);
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate /* close a dictionary */
318*7c478bd9Sstevel@tonic-gate void
fm_dc_closedict(fm_dc_handle_t * dhp)319*7c478bd9Sstevel@tonic-gate fm_dc_closedict(fm_dc_handle_t *dhp)
320*7c478bd9Sstevel@tonic-gate {
321*7c478bd9Sstevel@tonic-gate 	struct fm_dc_prop *props;
322*7c478bd9Sstevel@tonic-gate 	struct fm_dc_prop *oprops;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 1)
325*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "fm_dc_closedict: dhp 0x%p\n",
326*7c478bd9Sstevel@tonic-gate 		    (void *)dhp);
327*7c478bd9Sstevel@tonic-gate 	if (dhp->fp)
328*7c478bd9Sstevel@tonic-gate 		(void) fclose(dhp->fp);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	free((void *) dhp->dictname);
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	props = dhp->props;
333*7c478bd9Sstevel@tonic-gate 	while (props) {
334*7c478bd9Sstevel@tonic-gate 		if (props->lhs != NULL)
335*7c478bd9Sstevel@tonic-gate 			free((void *) props->lhs);
336*7c478bd9Sstevel@tonic-gate 		if (props->rhs != NULL)
337*7c478bd9Sstevel@tonic-gate 			free((void *) props->rhs);
338*7c478bd9Sstevel@tonic-gate 		oprops = props;
339*7c478bd9Sstevel@tonic-gate 		props = props->next;
340*7c478bd9Sstevel@tonic-gate 		free((void *) oprops);
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	free(dhp);
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate /* return maximum length (in bytes) of diagcodes for a given dictionary */
347*7c478bd9Sstevel@tonic-gate size_t
fm_dc_codelen(fm_dc_handle_t * dhp)348*7c478bd9Sstevel@tonic-gate fm_dc_codelen(fm_dc_handle_t *dhp)
349*7c478bd9Sstevel@tonic-gate {
350*7c478bd9Sstevel@tonic-gate 	size_t len = strlen(dhp->dictname);
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	/* only one version so far, so dhp->version isn't checked */
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 2)
355*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "fm_dc_codelen: dhp 0x%p: %d\n",
356*7c478bd9Sstevel@tonic-gate 		    (void *)dhp, (int)(len + MAXCODELEN));
357*7c478bd9Sstevel@tonic-gate 	return (len + MAXCODELEN);
358*7c478bd9Sstevel@tonic-gate }
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate /* return number of strings in key for a given dictionary */
361*7c478bd9Sstevel@tonic-gate int
fm_dc_maxkey(fm_dc_handle_t * dhp)362*7c478bd9Sstevel@tonic-gate fm_dc_maxkey(fm_dc_handle_t *dhp)
363*7c478bd9Sstevel@tonic-gate {
364*7c478bd9Sstevel@tonic-gate 	/* only one version so far, so dhp->version isn't checked */
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	/* this interface counts the NULL entry */
367*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 2)
368*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "fm_dc_maxkey: dhp 0x%p: maxkey %d\n",
369*7c478bd9Sstevel@tonic-gate 		    (void *)dhp, dhp->maxkey + 1);
370*7c478bd9Sstevel@tonic-gate 	return (dhp->maxkey + 1);
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate /* given a key, construct a diagcode */
374*7c478bd9Sstevel@tonic-gate int
fm_dc_key2code(fm_dc_handle_t * dhp,const char * key[],char * code,size_t maxcode)375*7c478bd9Sstevel@tonic-gate fm_dc_key2code(fm_dc_handle_t *dhp,
376*7c478bd9Sstevel@tonic-gate     const char *key[], char *code, size_t maxcode)
377*7c478bd9Sstevel@tonic-gate {
378*7c478bd9Sstevel@tonic-gate 	char *debugstr = "";		/* error path debug prefix text */
379*7c478bd9Sstevel@tonic-gate 	int line = 0;			/* line number in dict */
380*7c478bd9Sstevel@tonic-gate 	char linebuf[DICTMAXLINE];	/* line read from dict */
381*7c478bd9Sstevel@tonic-gate 	const char *rhsp;		/* right-hand-side of entry */
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	/* only one version so far, so dhp->version isn't checked */
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 1) {
386*7c478bd9Sstevel@tonic-gate 		int nel;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
389*7c478bd9Sstevel@tonic-gate 		    "fm_dc_key2code: dhp 0x%p maxcode %lu ", (void *)dhp,
390*7c478bd9Sstevel@tonic-gate 		    (ulong_t)maxcode);
391*7c478bd9Sstevel@tonic-gate 		for (nel = 0; key[nel]; nel++)
392*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "\"%s\" ", key[nel]);
393*7c478bd9Sstevel@tonic-gate 	} else if (dhp->debug)
394*7c478bd9Sstevel@tonic-gate 		debugstr = "fm_dc_key2code: ";
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	/* sort the keys */
397*7c478bd9Sstevel@tonic-gate 	sortkey(key);
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	rewind(dhp->fp);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	while (fgets(linebuf, DICTMAXLINE, dhp->fp) != NULL) {
402*7c478bd9Sstevel@tonic-gate 		line++;
403*7c478bd9Sstevel@tonic-gate 		if (*linebuf == '\n' || *linebuf == '#')
404*7c478bd9Sstevel@tonic-gate 			continue;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 		/* first non-comment, non-blank line must be header */
407*7c478bd9Sstevel@tonic-gate 		if (strncmp(linebuf, Header, sizeof (Header) - 1) == 0)
408*7c478bd9Sstevel@tonic-gate 			continue;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 		if ((rhsp = keymatch(linebuf, key)) != NULL) {
411*7c478bd9Sstevel@tonic-gate 			char ndebugstr[MAXDEBUGSTR];
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 			if (dhp->debug > 1)
414*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "match line %d: ", line);
415*7c478bd9Sstevel@tonic-gate 			else {
416*7c478bd9Sstevel@tonic-gate 				(void) snprintf(ndebugstr, MAXDEBUGSTR,
417*7c478bd9Sstevel@tonic-gate 				    "fm_dc_key2code: dictionary line %d",
418*7c478bd9Sstevel@tonic-gate 				    line);
419*7c478bd9Sstevel@tonic-gate 				debugstr = ndebugstr;
420*7c478bd9Sstevel@tonic-gate 			}
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 			return (buildcode(dhp, rhsp, code, maxcode, debugstr));
423*7c478bd9Sstevel@tonic-gate 		}
424*7c478bd9Sstevel@tonic-gate 	}
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	/* no match */
427*7c478bd9Sstevel@tonic-gate 	if (dhp->debug)
428*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%sENOMSG no match\n", debugstr);
429*7c478bd9Sstevel@tonic-gate 	errno = ENOMSG;
430*7c478bd9Sstevel@tonic-gate 	return (-1);
431*7c478bd9Sstevel@tonic-gate }
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate /* given a diagcode, return the key (array of strings) */
434*7c478bd9Sstevel@tonic-gate int
fm_dc_code2key(fm_dc_handle_t * dhp,const char * code,char * key[],int maxkey)435*7c478bd9Sstevel@tonic-gate fm_dc_code2key(fm_dc_handle_t *dhp, const char *code,
436*7c478bd9Sstevel@tonic-gate     char *key[], int maxkey)
437*7c478bd9Sstevel@tonic-gate {
438*7c478bd9Sstevel@tonic-gate 	char *debugstr = "";		/* error path debug prefix text */
439*7c478bd9Sstevel@tonic-gate 	int line = 0;
440*7c478bd9Sstevel@tonic-gate 	char linebuf[DICTMAXLINE];
441*7c478bd9Sstevel@tonic-gate 	bitv *dictval;
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	/* only one version so far, so dhp->version isn't checked */
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 1)
446*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
447*7c478bd9Sstevel@tonic-gate 		    "fm_dc_code2key: dhp 0x%p code \"%s\" maxkey %d: ",
448*7c478bd9Sstevel@tonic-gate 		    (void *)dhp, code, maxkey);
449*7c478bd9Sstevel@tonic-gate 	else if (dhp->debug)
450*7c478bd9Sstevel@tonic-gate 		debugstr = "fm_dc_code2key: ";
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 	/* convert code back to bit vector */
453*7c478bd9Sstevel@tonic-gate 	if ((dictval = code2dictval(dhp, code)) == NULL) {
454*7c478bd9Sstevel@tonic-gate 		/* code2dictval() sets errno */
455*7c478bd9Sstevel@tonic-gate 		if (dhp->debug) {
456*7c478bd9Sstevel@tonic-gate 			int oerrno = errno;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 			/* handle expected types without printing a number */
459*7c478bd9Sstevel@tonic-gate 			if (errno == ENOMEM)
460*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
461*7c478bd9Sstevel@tonic-gate 				    "%sENOMEM code2dictval\n",
462*7c478bd9Sstevel@tonic-gate 				    debugstr);
463*7c478bd9Sstevel@tonic-gate 			else if (errno == EINVAL)
464*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
465*7c478bd9Sstevel@tonic-gate 				    "%sEINVAL code2dictval\n",
466*7c478bd9Sstevel@tonic-gate 				    debugstr);
467*7c478bd9Sstevel@tonic-gate 			else
468*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
469*7c478bd9Sstevel@tonic-gate 				    "%scode2dictval error %d\n",
470*7c478bd9Sstevel@tonic-gate 				    debugstr, oerrno);
471*7c478bd9Sstevel@tonic-gate 			errno = oerrno;
472*7c478bd9Sstevel@tonic-gate 		}
473*7c478bd9Sstevel@tonic-gate 		return (-1);
474*7c478bd9Sstevel@tonic-gate 	}
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	rewind(dhp->fp);
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	while (fgets(linebuf, DICTMAXLINE, dhp->fp) != NULL) {
479*7c478bd9Sstevel@tonic-gate 		char *ptr;
480*7c478bd9Sstevel@tonic-gate 		bitv *thisval;
481*7c478bd9Sstevel@tonic-gate 		char *beginp;
482*7c478bd9Sstevel@tonic-gate 		char *endp;
483*7c478bd9Sstevel@tonic-gate 		int nel;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 		line++;
486*7c478bd9Sstevel@tonic-gate 		if (*linebuf == '\n' || *linebuf == '#')
487*7c478bd9Sstevel@tonic-gate 			continue;
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 		/* first non-comment, non-blank line must be header */
490*7c478bd9Sstevel@tonic-gate 		if (strncmp(linebuf, Header, sizeof (Header) - 1) == 0)
491*7c478bd9Sstevel@tonic-gate 			continue;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 		if ((ptr = strchr(linebuf, '=')) == NULL)
494*7c478bd9Sstevel@tonic-gate 			continue;	/* ignore malformed entries */
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 		*ptr++ = '\0';
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 		/* pull in value from dictionary */
499*7c478bd9Sstevel@tonic-gate 		if ((thisval = bitv_strparse(ptr, MAXDATABITS)) == NULL) {
500*7c478bd9Sstevel@tonic-gate 			/* bitv_strparse() sets errno */
501*7c478bd9Sstevel@tonic-gate 			if (errno == ENOMEM) {
502*7c478bd9Sstevel@tonic-gate 				bitv_free(dictval);
503*7c478bd9Sstevel@tonic-gate 				if (dhp->debug)
504*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
505*7c478bd9Sstevel@tonic-gate 					    "%sENOMEM bitv_strparse\n",
506*7c478bd9Sstevel@tonic-gate 					    debugstr);
507*7c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
508*7c478bd9Sstevel@tonic-gate 				return (-1);
509*7c478bd9Sstevel@tonic-gate 			}
510*7c478bd9Sstevel@tonic-gate 			/* other than ENOMEM, trudge on... */
511*7c478bd9Sstevel@tonic-gate 			continue;
512*7c478bd9Sstevel@tonic-gate 		}
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 		if (bitv_cmp(thisval, dictval)) {
515*7c478bd9Sstevel@tonic-gate 			bitv_free(thisval);
516*7c478bd9Sstevel@tonic-gate 			continue;
517*7c478bd9Sstevel@tonic-gate 		}
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		/* if we got here, we found the match */
520*7c478bd9Sstevel@tonic-gate 		bitv_free(thisval);
521*7c478bd9Sstevel@tonic-gate 		bitv_free(dictval);
522*7c478bd9Sstevel@tonic-gate 		beginp = linebuf;
523*7c478bd9Sstevel@tonic-gate 		nel = 0;
524*7c478bd9Sstevel@tonic-gate 		for (;;) {
525*7c478bd9Sstevel@tonic-gate 			while (*beginp && isspace(*beginp))
526*7c478bd9Sstevel@tonic-gate 				beginp++;
527*7c478bd9Sstevel@tonic-gate 			if (*beginp == '\0') {
528*7c478bd9Sstevel@tonic-gate 				/* all done */
529*7c478bd9Sstevel@tonic-gate 				key[nel] = NULL;
530*7c478bd9Sstevel@tonic-gate 				return (0);
531*7c478bd9Sstevel@tonic-gate 			}
532*7c478bd9Sstevel@tonic-gate 			if (nel >= maxkey - 1) {
533*7c478bd9Sstevel@tonic-gate 				if (dhp->debug)
534*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
535*7c478bd9Sstevel@tonic-gate 					    "%sENOMEM maxkey %d\n",
536*7c478bd9Sstevel@tonic-gate 					    debugstr, maxkey);
537*7c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
538*7c478bd9Sstevel@tonic-gate 				return (-1);
539*7c478bd9Sstevel@tonic-gate 			}
540*7c478bd9Sstevel@tonic-gate 			for (endp = beginp; *endp && !isspace(*endp); endp++)
541*7c478bd9Sstevel@tonic-gate 				;
542*7c478bd9Sstevel@tonic-gate 			if (*endp)
543*7c478bd9Sstevel@tonic-gate 				*endp++ = '\0';
544*7c478bd9Sstevel@tonic-gate 			if ((key[nel++] = strdup(beginp)) == NULL) {
545*7c478bd9Sstevel@tonic-gate 				if (dhp->debug)
546*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
547*7c478bd9Sstevel@tonic-gate 					    "%sENOMEM strdup\n", debugstr);
548*7c478bd9Sstevel@tonic-gate 				errno = ENOMEM;
549*7c478bd9Sstevel@tonic-gate 				return (-1);
550*7c478bd9Sstevel@tonic-gate 			}
551*7c478bd9Sstevel@tonic-gate 			beginp = endp;
552*7c478bd9Sstevel@tonic-gate 		}
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	bitv_free(dictval);
556*7c478bd9Sstevel@tonic-gate 	if (dhp->debug)
557*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%sENOMSG\n", debugstr);
558*7c478bd9Sstevel@tonic-gate 	errno = ENOMSG;
559*7c478bd9Sstevel@tonic-gate 	return (-1);
560*7c478bd9Sstevel@tonic-gate }
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate /* return the right-hand side of a names property from the dict header */
563*7c478bd9Sstevel@tonic-gate const char *
fm_dc_getprop(fm_dc_handle_t * dhp,const char * name)564*7c478bd9Sstevel@tonic-gate fm_dc_getprop(fm_dc_handle_t *dhp, const char *name)
565*7c478bd9Sstevel@tonic-gate {
566*7c478bd9Sstevel@tonic-gate 	struct fm_dc_prop *props;
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	/* only one version so far, so dhp->version isn't checked */
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 2)
571*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "fm_dc_getprop: dhp 0x%p: \"%s\"",
572*7c478bd9Sstevel@tonic-gate 		    (void *)dhp, name);
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	for (props = dhp->props; props; props = props->next)
575*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, props->lhs) == 0)
576*7c478bd9Sstevel@tonic-gate 			break;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 2)
579*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "= \"%s\"\n",
580*7c478bd9Sstevel@tonic-gate 		    (props == NULL) ? "NULL" : props->rhs);
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	return ((props == NULL) ? NULL : props->rhs);
583*7c478bd9Sstevel@tonic-gate }
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate /* find the appropriate diagcode format for a given dictval */
586*7c478bd9Sstevel@tonic-gate static const struct info *
dictval2info(const bitv * bv)587*7c478bd9Sstevel@tonic-gate dictval2info(const bitv *bv)
588*7c478bd9Sstevel@tonic-gate {
589*7c478bd9Sstevel@tonic-gate 	int i;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (Info) / sizeof (*Info) - 1; i++)
592*7c478bd9Sstevel@tonic-gate 		if (!bitv_ge(bv, Info[i + 1].offset))
593*7c478bd9Sstevel@tonic-gate 			return (&Info[i]);
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	/* return largest format */
596*7c478bd9Sstevel@tonic-gate 	return (&Info[sizeof (Info) / sizeof (*Info) - 1]);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate /* lookup the diagcode parameters given the number of X's used */
600*7c478bd9Sstevel@tonic-gate static const struct info *
numx2info(int numx)601*7c478bd9Sstevel@tonic-gate numx2info(int numx)
602*7c478bd9Sstevel@tonic-gate {
603*7c478bd9Sstevel@tonic-gate 	int i;
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (Info) / sizeof (*Info); i++)
606*7c478bd9Sstevel@tonic-gate 		if (numx == Info[i].numx)
607*7c478bd9Sstevel@tonic-gate 			return (&Info[i]);
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	return (NULL);
610*7c478bd9Sstevel@tonic-gate }
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate /* for use with qsort() */
613*7c478bd9Sstevel@tonic-gate static int
mycmp(const void * a,const void * b)614*7c478bd9Sstevel@tonic-gate mycmp(const void *a, const void *b)
615*7c478bd9Sstevel@tonic-gate {
616*7c478bd9Sstevel@tonic-gate 	return (strcmp(*(char **)a, *(char **)b));
617*7c478bd9Sstevel@tonic-gate }
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate /*
620*7c478bd9Sstevel@tonic-gate  * sortkey -- make sure key[] array is lexically sorted and without repeats
621*7c478bd9Sstevel@tonic-gate  */
622*7c478bd9Sstevel@tonic-gate static void
sortkey(const char * key[])623*7c478bd9Sstevel@tonic-gate sortkey(const char *key[])
624*7c478bd9Sstevel@tonic-gate {
625*7c478bd9Sstevel@tonic-gate 	int nel;
626*7c478bd9Sstevel@tonic-gate 	int srci;	/* source index when iterating through key[] */
627*7c478bd9Sstevel@tonic-gate 	int dsti;	/* dest index when storing elements in key[] */
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	/* count the number of elements in key[] */
630*7c478bd9Sstevel@tonic-gate 	for (nel = 0; key[nel]; nel++)
631*7c478bd9Sstevel@tonic-gate 		;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	if (nel < 2)
634*7c478bd9Sstevel@tonic-gate 		return;		/* nothing to sort */
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	qsort((void *)key, nel, sizeof (char *), mycmp);
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	/* go through array and remove repeats */
639*7c478bd9Sstevel@tonic-gate 	dsti = 1;
640*7c478bd9Sstevel@tonic-gate 	for (srci = 1; srci < nel; srci++)
641*7c478bd9Sstevel@tonic-gate 		if (strcmp(key[srci], key[dsti - 1]) != 0)
642*7c478bd9Sstevel@tonic-gate 			key[dsti++] = key[srci];
643*7c478bd9Sstevel@tonic-gate 	key[dsti] = NULL;
644*7c478bd9Sstevel@tonic-gate }
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate /*
647*7c478bd9Sstevel@tonic-gate  * keymatch -- check for matching line from the dictionary
648*7c478bd9Sstevel@tonic-gate  *
649*7c478bd9Sstevel@tonic-gate  * assumes that the key[] array has already been lexically sorted.
650*7c478bd9Sstevel@tonic-gate  * returns NULL if no match, otherwise pointer to first character of RHS.
651*7c478bd9Sstevel@tonic-gate  */
652*7c478bd9Sstevel@tonic-gate static const char *
keymatch(const char * linebuf,const char * key[])653*7c478bd9Sstevel@tonic-gate keymatch(const char *linebuf, const char *key[])
654*7c478bd9Sstevel@tonic-gate {
655*7c478bd9Sstevel@tonic-gate 	int keynum = 0;
656*7c478bd9Sstevel@tonic-gate 	const char *ptr;
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	while (linebuf) {
659*7c478bd9Sstevel@tonic-gate 		/* skip any initial whitespace in front of name */
660*7c478bd9Sstevel@tonic-gate 		while (*linebuf && isspace(*linebuf))
661*7c478bd9Sstevel@tonic-gate 			linebuf++;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 		ptr = key[keynum];
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 		if (ptr == NULL && *linebuf == '=') {
666*7c478bd9Sstevel@tonic-gate 			/* match */
667*7c478bd9Sstevel@tonic-gate 			linebuf++;
668*7c478bd9Sstevel@tonic-gate 			while (*linebuf && isspace(*linebuf))
669*7c478bd9Sstevel@tonic-gate 				linebuf++;
670*7c478bd9Sstevel@tonic-gate 			return (linebuf);
671*7c478bd9Sstevel@tonic-gate 		} else if (ptr == NULL)
672*7c478bd9Sstevel@tonic-gate 			return (NULL);	/* dict had more strings for key */
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 		/* match the string */
675*7c478bd9Sstevel@tonic-gate 		while (*linebuf)
676*7c478bd9Sstevel@tonic-gate 			if (*ptr == '\0') {
677*7c478bd9Sstevel@tonic-gate 				if (isspace(*linebuf) || *linebuf == '=')
678*7c478bd9Sstevel@tonic-gate 					break;	/* match */
679*7c478bd9Sstevel@tonic-gate 				else
680*7c478bd9Sstevel@tonic-gate 					return (NULL);	/* dict string longer */
681*7c478bd9Sstevel@tonic-gate 			} else if (*linebuf != *ptr)
682*7c478bd9Sstevel@tonic-gate 				return (NULL);	/* string don't match */
683*7c478bd9Sstevel@tonic-gate 			else {
684*7c478bd9Sstevel@tonic-gate 				linebuf++;
685*7c478bd9Sstevel@tonic-gate 				ptr++;
686*7c478bd9Sstevel@tonic-gate 			}
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 		keynum++;
689*7c478bd9Sstevel@tonic-gate 	}
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	return (NULL);	/* no match */
692*7c478bd9Sstevel@tonic-gate }
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate /*
695*7c478bd9Sstevel@tonic-gate  * buildcode -- given the val from the dictionary, create the diagcode
696*7c478bd9Sstevel@tonic-gate  */
697*7c478bd9Sstevel@tonic-gate static int
buildcode(fm_dc_handle_t * dhp,const char * rhsp,char * code,size_t maxcode,char * debugstr)698*7c478bd9Sstevel@tonic-gate buildcode(fm_dc_handle_t *dhp, const char *rhsp,
699*7c478bd9Sstevel@tonic-gate     char *code, size_t maxcode, char *debugstr)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate 	char *codebegin = code;	/* remember start of code buffer */
702*7c478bd9Sstevel@tonic-gate 	const struct info *infop;	/* Info[] table entry */
703*7c478bd9Sstevel@tonic-gate 	unsigned long csum = 0;	/* checksum (CRC) of diagcode */
704*7c478bd9Sstevel@tonic-gate 	const char *ptr;
705*7c478bd9Sstevel@tonic-gate 	bitv *dictval;		/* value from dictionary */
706*7c478bd9Sstevel@tonic-gate 	bitv *allbits;		/* assembled diagcode in binary */
707*7c478bd9Sstevel@tonic-gate 	int bit;		/* for looping through bits */
708*7c478bd9Sstevel@tonic-gate 	int limbit;		/* upper bit limit when looping */
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	/* sanity check that buffer is large enough for diagcode */
711*7c478bd9Sstevel@tonic-gate 	if (maxcode < fm_dc_codelen(dhp)) {
712*7c478bd9Sstevel@tonic-gate 		if (dhp->debug)
713*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
714*7c478bd9Sstevel@tonic-gate 			    "%sENOMEM maxcode %lu < codelen %lu\n",
715*7c478bd9Sstevel@tonic-gate 			    debugstr, (ulong_t)maxcode,
716*7c478bd9Sstevel@tonic-gate 			    (ulong_t)fm_dc_codelen(dhp));
717*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
718*7c478bd9Sstevel@tonic-gate 		return (-1);
719*7c478bd9Sstevel@tonic-gate 	}
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	/* handle dictname part of checksum */
722*7c478bd9Sstevel@tonic-gate 	for (ptr = dhp->dictname; *ptr; ptr++) {
723*7c478bd9Sstevel@tonic-gate 		crc(&csum, (unsigned)*ptr);
724*7c478bd9Sstevel@tonic-gate 		*code++ = *ptr;
725*7c478bd9Sstevel@tonic-gate 	}
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	/* pull in value from dictionary */
728*7c478bd9Sstevel@tonic-gate 	if ((dictval = bitv_strparse(rhsp, MAXDATABITS)) == NULL) {
729*7c478bd9Sstevel@tonic-gate 		/* bitv_strparse() sets errno */
730*7c478bd9Sstevel@tonic-gate 		if (dhp->debug) {
731*7c478bd9Sstevel@tonic-gate 			int oerrno = errno;
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 			/* handle expected types without printing a number */
734*7c478bd9Sstevel@tonic-gate 			if (errno == ENOMEM)
735*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
736*7c478bd9Sstevel@tonic-gate 				    "%sENOMEM bitv_strparse\n",
737*7c478bd9Sstevel@tonic-gate 				    debugstr);
738*7c478bd9Sstevel@tonic-gate 			else if (errno == ERANGE)
739*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
740*7c478bd9Sstevel@tonic-gate 				    "%sERANGE bitv_strparse\n",
741*7c478bd9Sstevel@tonic-gate 				    debugstr);
742*7c478bd9Sstevel@tonic-gate 			else
743*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
744*7c478bd9Sstevel@tonic-gate 				    "%sbitv_strparse error %d\n",
745*7c478bd9Sstevel@tonic-gate 				    debugstr, oerrno);
746*7c478bd9Sstevel@tonic-gate 			errno = oerrno;
747*7c478bd9Sstevel@tonic-gate 		}
748*7c478bd9Sstevel@tonic-gate 		return (-1);
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	/* determine which format of code we're using */
752*7c478bd9Sstevel@tonic-gate 	infop = dictval2info(dictval);
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	/* subtract off the offset appropriate for format of code */
755*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 3)
756*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
757*7c478bd9Sstevel@tonic-gate 		    "%ssubtract offset %llu\n", debugstr, infop->offset);
758*7c478bd9Sstevel@tonic-gate 	if (bitv_sub(dictval, infop->offset) < 0) {
759*7c478bd9Sstevel@tonic-gate 		/*
760*7c478bd9Sstevel@tonic-gate 		 * this "cannot happen" since code format was chosen
761*7c478bd9Sstevel@tonic-gate 		 * so that offset will be smaller than dictval, and
762*7c478bd9Sstevel@tonic-gate 		 * dictval cannot be out of range since bitv_strparse()
763*7c478bd9Sstevel@tonic-gate 		 * should have caught it.
764*7c478bd9Sstevel@tonic-gate 		 */
765*7c478bd9Sstevel@tonic-gate 		if (dhp->debug)
766*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
767*7c478bd9Sstevel@tonic-gate 			    "%sERANGE from bitv_sub\n", debugstr);
768*7c478bd9Sstevel@tonic-gate 		bitv_free(dictval);
769*7c478bd9Sstevel@tonic-gate 		errno = ERANGE;
770*7c478bd9Sstevel@tonic-gate 		return (-1);
771*7c478bd9Sstevel@tonic-gate 	}
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	/* assemble all the bits for the diagcode */
774*7c478bd9Sstevel@tonic-gate 	if ((allbits = bitv_alloc()) == NULL) {
775*7c478bd9Sstevel@tonic-gate 		bitv_free(dictval);
776*7c478bd9Sstevel@tonic-gate 		if (dhp->debug)
777*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
778*7c478bd9Sstevel@tonic-gate 			    "%sENOMEM from bitv_alloc\n", debugstr);
779*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
780*7c478bd9Sstevel@tonic-gate 		return (-1);
781*7c478bd9Sstevel@tonic-gate 	}
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	/*
784*7c478bd9Sstevel@tonic-gate 	 * construct the full diagcode by shifting in information:
785*7c478bd9Sstevel@tonic-gate 	 *	- 2 bit code type, set to 01
786*7c478bd9Sstevel@tonic-gate 	 *	- 2 bit size field
787*7c478bd9Sstevel@tonic-gate 	 *	- the databits of the dictionary code itself
788*7c478bd9Sstevel@tonic-gate 	 */
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	bitv_shiftin(allbits, 2, 1);
791*7c478bd9Sstevel@tonic-gate 	bitv_shiftin(allbits, 2, infop->sizeval);
792*7c478bd9Sstevel@tonic-gate 	bitv_shiftinv(allbits, infop->databits, dictval);
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	/* insert zeros for checksum */
795*7c478bd9Sstevel@tonic-gate 	bitv_shiftin(allbits, infop->csumbits, 0);
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 	/* compute checksum */
798*7c478bd9Sstevel@tonic-gate 	limbit = infop->numx * 5;
799*7c478bd9Sstevel@tonic-gate 	for (bit = 0; bit < infop->numx; bit++) {
800*7c478bd9Sstevel@tonic-gate 		crc(&csum, bitv_chunk(allbits, limbit, limbit - 5));
801*7c478bd9Sstevel@tonic-gate 		limbit -= 5;
802*7c478bd9Sstevel@tonic-gate 	}
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	/* insert the computed checksum */
805*7c478bd9Sstevel@tonic-gate 	bitv_setlo(allbits, infop->csumbits, (unsigned)csum);
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	/* encode binary values according to alphabet */
808*7c478bd9Sstevel@tonic-gate 	limbit = infop->numx * 5;
809*7c478bd9Sstevel@tonic-gate 	for (bit = 0; bit < infop->numx; bit++) {
810*7c478bd9Sstevel@tonic-gate 		if (bit % 4 == 0)
811*7c478bd9Sstevel@tonic-gate 			*code++ = '-';
812*7c478bd9Sstevel@tonic-gate 		*code++ = Alphabet[bitv_chunk(allbits, limbit, limbit - 5)];
813*7c478bd9Sstevel@tonic-gate 		limbit -= 5;
814*7c478bd9Sstevel@tonic-gate 	}
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	*code = '\0';
817*7c478bd9Sstevel@tonic-gate 	bitv_free(allbits);
818*7c478bd9Sstevel@tonic-gate 	bitv_free(dictval);
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	if (dhp->debug > 1)
821*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "code \"%s\"\n", codebegin);
822*7c478bd9Sstevel@tonic-gate 	return (0);
823*7c478bd9Sstevel@tonic-gate }
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate /*
826*7c478bd9Sstevel@tonic-gate  * code2dictval -- convert a diagcode back to a bit vector
827*7c478bd9Sstevel@tonic-gate  */
828*7c478bd9Sstevel@tonic-gate static bitv *
code2dictval(fm_dc_handle_t * dhp,const char * code)829*7c478bd9Sstevel@tonic-gate code2dictval(fm_dc_handle_t *dhp, const char *code)
830*7c478bd9Sstevel@tonic-gate {
831*7c478bd9Sstevel@tonic-gate 	const struct info *infop;
832*7c478bd9Sstevel@tonic-gate 	int len = strlen(dhp->dictname);
833*7c478bd9Sstevel@tonic-gate 	bitv *allbits;
834*7c478bd9Sstevel@tonic-gate 	bitv *dictval;
835*7c478bd9Sstevel@tonic-gate 	int numx;		/* number of X's we count */
836*7c478bd9Sstevel@tonic-gate 	unsigned long ocsum;	/* original checksum in code */
837*7c478bd9Sstevel@tonic-gate 	unsigned long csum;	/* our computed checksum */
838*7c478bd9Sstevel@tonic-gate 	int bit;		/* for looping through bits */
839*7c478bd9Sstevel@tonic-gate 	int limbit;		/* upper bit limit when looping */
840*7c478bd9Sstevel@tonic-gate 	const char *ptr;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	/* check dictname part of code */
843*7c478bd9Sstevel@tonic-gate 	if (strncasecmp(code, dhp->dictname, len) ||
844*7c478bd9Sstevel@tonic-gate 	    code[len] != '-') {
845*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
846*7c478bd9Sstevel@tonic-gate 		return (NULL);
847*7c478bd9Sstevel@tonic-gate 	}
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	/* convert code back to a bit vector */
850*7c478bd9Sstevel@tonic-gate 	if ((allbits = bitv_alloc()) == NULL) {
851*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
852*7c478bd9Sstevel@tonic-gate 		return (NULL);
853*7c478bd9Sstevel@tonic-gate 	}
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	/* we verified it began with dictname and a dash, so skip it */
856*7c478bd9Sstevel@tonic-gate 	code = &code[len + 1];
857*7c478bd9Sstevel@tonic-gate 	numx = 0;
858*7c478bd9Sstevel@tonic-gate 	/* be forgiving about misplaced dashes */
859*7c478bd9Sstevel@tonic-gate 	for (; *code; code++)
860*7c478bd9Sstevel@tonic-gate 		if (*code == '-')
861*7c478bd9Sstevel@tonic-gate 			continue;
862*7c478bd9Sstevel@tonic-gate 		else {
863*7c478bd9Sstevel@tonic-gate 			unsigned val;
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 			for (val = 0; Alphabet[val]; val++)
866*7c478bd9Sstevel@tonic-gate 				if (*code == Alphabet[val])
867*7c478bd9Sstevel@tonic-gate 					break;
868*7c478bd9Sstevel@tonic-gate 			if (Alphabet[val] == '\0') {
869*7c478bd9Sstevel@tonic-gate 				bitv_free(allbits);
870*7c478bd9Sstevel@tonic-gate 				errno = EINVAL;
871*7c478bd9Sstevel@tonic-gate 				return (NULL);
872*7c478bd9Sstevel@tonic-gate 			}
873*7c478bd9Sstevel@tonic-gate 			bitv_shiftin(allbits, 5, val);
874*7c478bd9Sstevel@tonic-gate 			numx++;
875*7c478bd9Sstevel@tonic-gate 		}
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	if ((infop = numx2info(numx)) == NULL) {
878*7c478bd9Sstevel@tonic-gate 		bitv_free(allbits);
879*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
880*7c478bd9Sstevel@tonic-gate 		return (NULL);
881*7c478bd9Sstevel@tonic-gate 	}
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	/* now pull out the csum */
884*7c478bd9Sstevel@tonic-gate 	ocsum = bitv_chunk(allbits, infop->csumbits, 0);
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	/* set the csum bits to zero */
887*7c478bd9Sstevel@tonic-gate 	bitv_setlo(allbits, infop->csumbits, 0);
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	/* calculate the checksum and see if it matches */
890*7c478bd9Sstevel@tonic-gate 	csum = 0;
891*7c478bd9Sstevel@tonic-gate 	for (ptr = dhp->dictname; *ptr; ptr++)
892*7c478bd9Sstevel@tonic-gate 		crc(&csum, (unsigned)*ptr);
893*7c478bd9Sstevel@tonic-gate 	limbit = numx * 5;
894*7c478bd9Sstevel@tonic-gate 	for (bit = 0; bit < numx; bit++) {
895*7c478bd9Sstevel@tonic-gate 		crc(&csum, bitv_chunk(allbits, limbit, limbit - 5));
896*7c478bd9Sstevel@tonic-gate 		limbit -= 5;
897*7c478bd9Sstevel@tonic-gate 	}
898*7c478bd9Sstevel@tonic-gate 	csum &= (1 << infop->csumbits) - 1;
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 	if (csum != ocsum) {
901*7c478bd9Sstevel@tonic-gate 		bitv_free(allbits);
902*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
903*7c478bd9Sstevel@tonic-gate 		return (NULL);
904*7c478bd9Sstevel@tonic-gate 	}
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 	/* code looks okay, just return dictval portion */
907*7c478bd9Sstevel@tonic-gate 	if ((dictval = bitv_alloc()) == NULL) {
908*7c478bd9Sstevel@tonic-gate 		bitv_free(allbits);
909*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
910*7c478bd9Sstevel@tonic-gate 		return (NULL);
911*7c478bd9Sstevel@tonic-gate 	}
912*7c478bd9Sstevel@tonic-gate 	limbit = infop->csumbits + infop->databits;
913*7c478bd9Sstevel@tonic-gate 	while (limbit > infop->csumbits) {
914*7c478bd9Sstevel@tonic-gate 		bitv_shiftin(dictval, 1,
915*7c478bd9Sstevel@tonic-gate 		    bitv_chunk(allbits, limbit, limbit - 1));
916*7c478bd9Sstevel@tonic-gate 		limbit--;
917*7c478bd9Sstevel@tonic-gate 	}
918*7c478bd9Sstevel@tonic-gate 	bitv_free(allbits);
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	/* add in the offset appropriate for the length of code being used */
921*7c478bd9Sstevel@tonic-gate 	if (bitv_add(dictval, infop->offset) < 0) {
922*7c478bd9Sstevel@tonic-gate 		/*
923*7c478bd9Sstevel@tonic-gate 		 * overflow "cannot happen" since we've pulled in
924*7c478bd9Sstevel@tonic-gate 		 * a given number of bits from the code and the offset
925*7c478bd9Sstevel@tonic-gate 		 * is designed not to overflow...
926*7c478bd9Sstevel@tonic-gate 		 */
927*7c478bd9Sstevel@tonic-gate 		bitv_free(dictval);
928*7c478bd9Sstevel@tonic-gate 		errno = ERANGE;
929*7c478bd9Sstevel@tonic-gate 		return (NULL);
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	return (dictval);
933*7c478bd9Sstevel@tonic-gate }
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate /*
937*7c478bd9Sstevel@tonic-gate  * private routines to parse a line into name/value pairs...
938*7c478bd9Sstevel@tonic-gate  *
939*7c478bd9Sstevel@tonic-gate  */
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate /*
942*7c478bd9Sstevel@tonic-gate  * startparse -- record starting of buffer containing name=value pairs
943*7c478bd9Sstevel@tonic-gate  */
944*7c478bd9Sstevel@tonic-gate static void
startparse(struct parsestate * ps,char * ptr)945*7c478bd9Sstevel@tonic-gate startparse(struct parsestate *ps, char *ptr)
946*7c478bd9Sstevel@tonic-gate {
947*7c478bd9Sstevel@tonic-gate 	ps->parseptr = ptr;
948*7c478bd9Sstevel@tonic-gate }
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate /*
951*7c478bd9Sstevel@tonic-gate  * nextlhs -- return next left-hand-side of name=value pair, or NULL
952*7c478bd9Sstevel@tonic-gate  *
953*7c478bd9Sstevel@tonic-gate  * whitespace around the '=' is allowed for, but not required.  the
954*7c478bd9Sstevel@tonic-gate  * lhs is a simple string that does not contain any whitespace or an
955*7c478bd9Sstevel@tonic-gate  * embedded equals sign.  no escaped characters, quotes, etc. are
956*7c478bd9Sstevel@tonic-gate  * honored here.
957*7c478bd9Sstevel@tonic-gate  *
958*7c478bd9Sstevel@tonic-gate  * this routine also parses the rhs and saves a pointer to it
959*7c478bd9Sstevel@tonic-gate  * in Rhsp so that nextrhs() can return it.  if nextrhs() never
960*7c478bd9Sstevel@tonic-gate  * gets called, we continue looking for the next lhs *after* any
961*7c478bd9Sstevel@tonic-gate  * rhs that was there.
962*7c478bd9Sstevel@tonic-gate  */
963*7c478bd9Sstevel@tonic-gate static char *
nextlhs(struct parsestate * ps)964*7c478bd9Sstevel@tonic-gate nextlhs(struct parsestate *ps)
965*7c478bd9Sstevel@tonic-gate {
966*7c478bd9Sstevel@tonic-gate 	char *lhsp;
967*7c478bd9Sstevel@tonic-gate 	char *copyto;
968*7c478bd9Sstevel@tonic-gate 	int equals = 0;
969*7c478bd9Sstevel@tonic-gate 	int quote = 0;
970*7c478bd9Sstevel@tonic-gate 	int backslash = 0;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	/* skip whitespace */
973*7c478bd9Sstevel@tonic-gate 	while (*ps->parseptr && isspace(*ps->parseptr))
974*7c478bd9Sstevel@tonic-gate 		ps->parseptr++;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 	/* anything left? */
977*7c478bd9Sstevel@tonic-gate 	if (*ps->parseptr == '\0')
978*7c478bd9Sstevel@tonic-gate 		return (NULL);
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	/* remember start of lhs, assume no rhs until we see '=' */
981*7c478bd9Sstevel@tonic-gate 	lhsp = ps->parseptr;
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	/* find end of token, no escaped chars, quotes, etc. on lhs */
984*7c478bd9Sstevel@tonic-gate 	while (*ps->parseptr && !isspace(*ps->parseptr))
985*7c478bd9Sstevel@tonic-gate 		if (*ps->parseptr == '=') {
986*7c478bd9Sstevel@tonic-gate 			equals = 1;
987*7c478bd9Sstevel@tonic-gate 			break;
988*7c478bd9Sstevel@tonic-gate 		} else
989*7c478bd9Sstevel@tonic-gate 			ps->parseptr++;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 	/* null terminate the token, possibly nuking the '=' itself */
992*7c478bd9Sstevel@tonic-gate 	*ps->parseptr++ = '\0';
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	/* if we haven't seen an '=', see if it happens after whitespace */
995*7c478bd9Sstevel@tonic-gate 	if (!equals) {
996*7c478bd9Sstevel@tonic-gate 		while (*ps->parseptr && isspace(*ps->parseptr))
997*7c478bd9Sstevel@tonic-gate 			ps->parseptr++;
998*7c478bd9Sstevel@tonic-gate 		if (*ps->parseptr == '=') {
999*7c478bd9Sstevel@tonic-gate 			equals = 1;
1000*7c478bd9Sstevel@tonic-gate 			ps->parseptr++;
1001*7c478bd9Sstevel@tonic-gate 		}
1002*7c478bd9Sstevel@tonic-gate 	}
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	/* skip whitespace */
1005*7c478bd9Sstevel@tonic-gate 	while (*ps->parseptr && isspace(*ps->parseptr))
1006*7c478bd9Sstevel@tonic-gate 		ps->parseptr++;
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	/* isolate the rhs if it is there */
1009*7c478bd9Sstevel@tonic-gate 	if (!equals || *ps->parseptr == '\0') {
1010*7c478bd9Sstevel@tonic-gate 		ps->rhsp = NULL;
1011*7c478bd9Sstevel@tonic-gate 		return (lhsp);
1012*7c478bd9Sstevel@tonic-gate 	}
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 	if (*ps->parseptr == '"') {
1015*7c478bd9Sstevel@tonic-gate 		quote = 1;
1016*7c478bd9Sstevel@tonic-gate 		ps->parseptr++;
1017*7c478bd9Sstevel@tonic-gate 	}
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate 	/* remember the beginning of the rhs */
1020*7c478bd9Sstevel@tonic-gate 	ps->rhsp = copyto = ps->parseptr;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	/* now scan to the end of the rhs */
1023*7c478bd9Sstevel@tonic-gate 	while (*ps->parseptr) {
1024*7c478bd9Sstevel@tonic-gate 		if (backslash) {
1025*7c478bd9Sstevel@tonic-gate 			switch (*ps->parseptr) {
1026*7c478bd9Sstevel@tonic-gate 			case 't':
1027*7c478bd9Sstevel@tonic-gate 				*copyto++ = '\t';
1028*7c478bd9Sstevel@tonic-gate 				break;
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 			case 'r':
1031*7c478bd9Sstevel@tonic-gate 				*copyto++ = '\r';
1032*7c478bd9Sstevel@tonic-gate 				break;
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 			case 'n':
1035*7c478bd9Sstevel@tonic-gate 				*copyto++ = '\n';
1036*7c478bd9Sstevel@tonic-gate 				break;
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 			case 'f':
1039*7c478bd9Sstevel@tonic-gate 				*copyto++ = '\f';
1040*7c478bd9Sstevel@tonic-gate 				break;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 			default:
1043*7c478bd9Sstevel@tonic-gate 				*copyto++ = *ps->parseptr;
1044*7c478bd9Sstevel@tonic-gate 				break;
1045*7c478bd9Sstevel@tonic-gate 			}
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 			backslash = 0;
1048*7c478bd9Sstevel@tonic-gate 		} else if (*ps->parseptr == '\\')
1049*7c478bd9Sstevel@tonic-gate 			backslash = 1;
1050*7c478bd9Sstevel@tonic-gate 		else if (quote) {
1051*7c478bd9Sstevel@tonic-gate 			if (*ps->parseptr == '"') {
1052*7c478bd9Sstevel@tonic-gate 				ps->parseptr++;
1053*7c478bd9Sstevel@tonic-gate 				break;		/* end of quoted string */
1054*7c478bd9Sstevel@tonic-gate 			} else
1055*7c478bd9Sstevel@tonic-gate 				*copyto++ = *ps->parseptr;
1056*7c478bd9Sstevel@tonic-gate 		} else if (!isspace(*ps->parseptr))
1057*7c478bd9Sstevel@tonic-gate 			*copyto++ = *ps->parseptr;
1058*7c478bd9Sstevel@tonic-gate 		else {
1059*7c478bd9Sstevel@tonic-gate 			ps->parseptr++;
1060*7c478bd9Sstevel@tonic-gate 			break;	/* rhs terminated by whitespace */
1061*7c478bd9Sstevel@tonic-gate 		}
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 		ps->parseptr++;
1064*7c478bd9Sstevel@tonic-gate 	}
1065*7c478bd9Sstevel@tonic-gate 	*copyto = '\0';
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	return (lhsp);
1068*7c478bd9Sstevel@tonic-gate }
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate /*
1071*7c478bd9Sstevel@tonic-gate  * nextrhs -- return right-hand-side of name=value pair, or NULL
1072*7c478bd9Sstevel@tonic-gate  *
1073*7c478bd9Sstevel@tonic-gate  * this routine can only be used after a lhs has been found with
1074*7c478bd9Sstevel@tonic-gate  * nextlhs().  the rhs consists of a string with no whitespace in it,
1075*7c478bd9Sstevel@tonic-gate  * unless the whitespace is escaped with a backslash.  surrounding
1076*7c478bd9Sstevel@tonic-gate  * a string with double quotes is also supported here, as are the
1077*7c478bd9Sstevel@tonic-gate  * common C escape sequences like \t and \n.
1078*7c478bd9Sstevel@tonic-gate  *
1079*7c478bd9Sstevel@tonic-gate  * nextlhs() actually does all the hard work.  we just return any
1080*7c478bd9Sstevel@tonic-gate  * rhs that was found by that routine.
1081*7c478bd9Sstevel@tonic-gate  */
1082*7c478bd9Sstevel@tonic-gate static char *
nextrhs(struct parsestate * ps)1083*7c478bd9Sstevel@tonic-gate nextrhs(struct parsestate *ps)
1084*7c478bd9Sstevel@tonic-gate {
1085*7c478bd9Sstevel@tonic-gate 	return (ps->rhsp);
1086*7c478bd9Sstevel@tonic-gate }
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate /*
1090*7c478bd9Sstevel@tonic-gate  * private routines to manipulate bit vectors (i.e. large integers)
1091*7c478bd9Sstevel@tonic-gate  *
1092*7c478bd9Sstevel@tonic-gate  * if these bit vector routines are ever supposed to be more
1093*7c478bd9Sstevel@tonic-gate  * general, the desired length should be passed in to bitv_alloc()
1094*7c478bd9Sstevel@tonic-gate  * instead of defining a maximum here.  but knowing the max ahead
1095*7c478bd9Sstevel@tonic-gate  * of time allows for simpler code and we know the max that will
1096*7c478bd9Sstevel@tonic-gate  * fit into a diagcode.  on the minimum side, the below define
1097*7c478bd9Sstevel@tonic-gate  * must be at least sizeof (unsigned).
1098*7c478bd9Sstevel@tonic-gate  */
1099*7c478bd9Sstevel@tonic-gate #define	BITV_MAX_BYTES 15
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate /* data structure used to hold a bit vector */
1102*7c478bd9Sstevel@tonic-gate struct bitv {
1103*7c478bd9Sstevel@tonic-gate 	unsigned char v[BITV_MAX_BYTES];
1104*7c478bd9Sstevel@tonic-gate };
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate /* allocate a new, zeroed out bit vector */
1107*7c478bd9Sstevel@tonic-gate static bitv *
bitv_alloc(void)1108*7c478bd9Sstevel@tonic-gate bitv_alloc(void)
1109*7c478bd9Sstevel@tonic-gate {
1110*7c478bd9Sstevel@tonic-gate 	int i;
1111*7c478bd9Sstevel@tonic-gate 	struct bitv *bv = malloc(sizeof (*bv));
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 	if (bv)
1114*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < BITV_MAX_BYTES; i++)
1115*7c478bd9Sstevel@tonic-gate 			bv->v[i] = 0;
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate 	return (bv);
1118*7c478bd9Sstevel@tonic-gate }
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate /* free a bit vector that was allocated with bitv_alloc() */
1121*7c478bd9Sstevel@tonic-gate static void
bitv_free(bitv * bv)1122*7c478bd9Sstevel@tonic-gate bitv_free(bitv *bv)
1123*7c478bd9Sstevel@tonic-gate {
1124*7c478bd9Sstevel@tonic-gate 	free(bv);
1125*7c478bd9Sstevel@tonic-gate }
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate /* shift left a bit vector by a given number of bits.  fill with zeros. */
1128*7c478bd9Sstevel@tonic-gate static void
bitv_shift(bitv * bv,unsigned bits)1129*7c478bd9Sstevel@tonic-gate bitv_shift(bitv *bv, unsigned bits)
1130*7c478bd9Sstevel@tonic-gate {
1131*7c478bd9Sstevel@tonic-gate 	while (bits > 0) {
1132*7c478bd9Sstevel@tonic-gate 		unsigned iterbits = bits;
1133*7c478bd9Sstevel@tonic-gate 		int i;
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 		/* how many bits this iteration?  8 max. */
1136*7c478bd9Sstevel@tonic-gate 		if (iterbits > 8)
1137*7c478bd9Sstevel@tonic-gate 			iterbits = 8;
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 		for (i = BITV_MAX_BYTES - 1; i > 0; i--) {
1140*7c478bd9Sstevel@tonic-gate 			bv->v[i] <<= iterbits;
1141*7c478bd9Sstevel@tonic-gate 			bv->v[i] |= bv->v[i - 1] >> (8 - iterbits);
1142*7c478bd9Sstevel@tonic-gate 		}
1143*7c478bd9Sstevel@tonic-gate 		bv->v[0] <<= iterbits;
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 		bits -= iterbits;
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate }
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate /* force a given number of bits to a specific value */
1150*7c478bd9Sstevel@tonic-gate static void
bitv_setlo(bitv * bv,unsigned bits,unsigned val)1151*7c478bd9Sstevel@tonic-gate bitv_setlo(bitv *bv, unsigned bits, unsigned val)
1152*7c478bd9Sstevel@tonic-gate {
1153*7c478bd9Sstevel@tonic-gate 	int i = 0;
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	/* assumption: bits * 8 <= sizeof (val) */
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	while (bits > 0) {
1158*7c478bd9Sstevel@tonic-gate 		unsigned iterbits = bits;
1159*7c478bd9Sstevel@tonic-gate 		unsigned mask;
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 		if (iterbits > 8)
1162*7c478bd9Sstevel@tonic-gate 			iterbits = 8;
1163*7c478bd9Sstevel@tonic-gate 
1164*7c478bd9Sstevel@tonic-gate 		mask = (1 << iterbits) - 1;
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate 		bv->v[i] &= ~mask;
1167*7c478bd9Sstevel@tonic-gate 		bv->v[i] |= val & mask;
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 		val >>= iterbits;
1170*7c478bd9Sstevel@tonic-gate 		bits -= iterbits;
1171*7c478bd9Sstevel@tonic-gate 		/*
1172*7c478bd9Sstevel@tonic-gate 		 * the following can't go off end of bv->v[] since
1173*7c478bd9Sstevel@tonic-gate 		 * BITV_MAX_BYTES is assumed to be at least sizeof
1174*7c478bd9Sstevel@tonic-gate 		 * unsigned and val can't be more than sizeof unsigned
1175*7c478bd9Sstevel@tonic-gate 		 * bytes long.
1176*7c478bd9Sstevel@tonic-gate 		 */
1177*7c478bd9Sstevel@tonic-gate 		i++;
1178*7c478bd9Sstevel@tonic-gate 	}
1179*7c478bd9Sstevel@tonic-gate }
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate /* given a value and number of bits, shift it in from the right */
1182*7c478bd9Sstevel@tonic-gate static void
bitv_shiftin(bitv * bv,unsigned bits,unsigned val)1183*7c478bd9Sstevel@tonic-gate bitv_shiftin(bitv *bv, unsigned bits, unsigned val)
1184*7c478bd9Sstevel@tonic-gate {
1185*7c478bd9Sstevel@tonic-gate 	bitv_shift(bv, bits);
1186*7c478bd9Sstevel@tonic-gate 	bitv_setlo(bv, bits, val);
1187*7c478bd9Sstevel@tonic-gate }
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate /* given a bit vector and a number of bits, shift it in from the right */
1190*7c478bd9Sstevel@tonic-gate static void
bitv_shiftinv(bitv * bv,unsigned bits,const bitv * inbv)1191*7c478bd9Sstevel@tonic-gate bitv_shiftinv(bitv *bv, unsigned bits, const bitv *inbv)
1192*7c478bd9Sstevel@tonic-gate {
1193*7c478bd9Sstevel@tonic-gate 	int byteindex = bits / 8;
1194*7c478bd9Sstevel@tonic-gate 	int iterbits = bits % 8;
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 	/* first handle partial byte shift in */
1197*7c478bd9Sstevel@tonic-gate 	bitv_shiftin(bv, iterbits, inbv->v[byteindex--]);
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	/* now handle any remaining full byte shift ins */
1200*7c478bd9Sstevel@tonic-gate 	while (byteindex >= 0)
1201*7c478bd9Sstevel@tonic-gate 		bitv_shiftin(bv, 8, inbv->v[byteindex--]);
1202*7c478bd9Sstevel@tonic-gate }
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate /* return the number of bits required to hold the current bit vector's value */
1205*7c478bd9Sstevel@tonic-gate static int
bitv_bits(const bitv * bv)1206*7c478bd9Sstevel@tonic-gate bitv_bits(const bitv *bv)
1207*7c478bd9Sstevel@tonic-gate {
1208*7c478bd9Sstevel@tonic-gate 	int i;
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	for (i = BITV_MAX_BYTES - 1; i >= 0; i--)
1211*7c478bd9Sstevel@tonic-gate 		if (bv->v[i]) {
1212*7c478bd9Sstevel@tonic-gate 			int bit;
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 			for (bit = 7; bit >= 0; bit--)
1215*7c478bd9Sstevel@tonic-gate 				if ((bv->v[i] >> bit) & 1)
1216*7c478bd9Sstevel@tonic-gate 					return (i * 8 + bit + 1);
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 			/* this can't happen, so do *something* */
1219*7c478bd9Sstevel@tonic-gate 			return ((i + 1) * 8);
1220*7c478bd9Sstevel@tonic-gate 		}
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	return (0);
1223*7c478bd9Sstevel@tonic-gate }
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate /* extract chunks of bits from bit vector */
1226*7c478bd9Sstevel@tonic-gate static unsigned
bitv_chunk(const bitv * bv,unsigned limbit,unsigned lobit)1227*7c478bd9Sstevel@tonic-gate bitv_chunk(const bitv *bv, unsigned limbit, unsigned lobit)
1228*7c478bd9Sstevel@tonic-gate {
1229*7c478bd9Sstevel@tonic-gate 	unsigned retval = 0;
1230*7c478bd9Sstevel@tonic-gate 	int bit;
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	/*
1233*7c478bd9Sstevel@tonic-gate 	 * entry assumptions:
1234*7c478bd9Sstevel@tonic-gate 	 *	limbit > lobit
1235*7c478bd9Sstevel@tonic-gate 	 *	limbit - lobit <= sizeof (unsigned) * 8
1236*7c478bd9Sstevel@tonic-gate 	 */
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	for (bit = limbit - 1; bit >= 0 && bit >= lobit; bit--) {
1239*7c478bd9Sstevel@tonic-gate 		retval <<= 1;
1240*7c478bd9Sstevel@tonic-gate 		retval |= (bv->v[bit / 8] >> (bit % 8)) & 1;
1241*7c478bd9Sstevel@tonic-gate 	}
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	return (retval);
1244*7c478bd9Sstevel@tonic-gate }
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate /*
1247*7c478bd9Sstevel@tonic-gate  * multiply by a given value
1248*7c478bd9Sstevel@tonic-gate  *
1249*7c478bd9Sstevel@tonic-gate  *	on overflow, bit vector will hold least significant BITV_MAX_BYTES,
1250*7c478bd9Sstevel@tonic-gate  *	return value will be -1, and errno will be ERANGE.  otherwise
1251*7c478bd9Sstevel@tonic-gate  *	return is zero and bit vector holds the product.
1252*7c478bd9Sstevel@tonic-gate  */
1253*7c478bd9Sstevel@tonic-gate static int
bitv_mul(bitv * bv,unsigned long long val)1254*7c478bd9Sstevel@tonic-gate bitv_mul(bitv *bv, unsigned long long val)
1255*7c478bd9Sstevel@tonic-gate {
1256*7c478bd9Sstevel@tonic-gate 	unsigned short result;
1257*7c478bd9Sstevel@tonic-gate 	unsigned char prod[BITV_MAX_BYTES];
1258*7c478bd9Sstevel@tonic-gate 	unsigned k = 0;
1259*7c478bd9Sstevel@tonic-gate 	int valbyte;
1260*7c478bd9Sstevel@tonic-gate 	int bvbyte;
1261*7c478bd9Sstevel@tonic-gate 	int i;
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	/* start with a zeroed out bit vector to hold result */
1264*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < BITV_MAX_BYTES; i++)
1265*7c478bd9Sstevel@tonic-gate 		prod[i] = 0;
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate 	/* from most-significant byte of val to least... */
1268*7c478bd9Sstevel@tonic-gate 	for (valbyte = 0; valbyte < sizeof (val); valbyte++)
1269*7c478bd9Sstevel@tonic-gate 		/* from most significant byte of bv to least */
1270*7c478bd9Sstevel@tonic-gate 		for (bvbyte = 0; bvbyte < BITV_MAX_BYTES; bvbyte++) {
1271*7c478bd9Sstevel@tonic-gate 			result = ((val >> (valbyte * 8)) & 0xff) *
1272*7c478bd9Sstevel@tonic-gate 			    bv->v[bvbyte] + k;
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 			if (valbyte + bvbyte >= BITV_MAX_BYTES) {
1275*7c478bd9Sstevel@tonic-gate 				/*
1276*7c478bd9Sstevel@tonic-gate 				 * we're not storing digits past
1277*7c478bd9Sstevel@tonic-gate 				 * BITV_MAX_BYTES, so if they aren't
1278*7c478bd9Sstevel@tonic-gate 				 * zeros, then signal an overflow.
1279*7c478bd9Sstevel@tonic-gate 				 */
1280*7c478bd9Sstevel@tonic-gate 				if (result & 0xff) {
1281*7c478bd9Sstevel@tonic-gate 					errno = ERANGE;
1282*7c478bd9Sstevel@tonic-gate 					return (-1);
1283*7c478bd9Sstevel@tonic-gate 				}
1284*7c478bd9Sstevel@tonic-gate 			} else
1285*7c478bd9Sstevel@tonic-gate 				prod[valbyte + bvbyte] += result & 0xff;
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 			/* "carry the 1..." */
1288*7c478bd9Sstevel@tonic-gate 			k = result >> 8;
1289*7c478bd9Sstevel@tonic-gate 		}
1290*7c478bd9Sstevel@tonic-gate 
1291*7c478bd9Sstevel@tonic-gate 	/* store result in bv */
1292*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < BITV_MAX_BYTES; i++)
1293*7c478bd9Sstevel@tonic-gate 		bv->v[i] = prod[i];
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate 	return (0);
1296*7c478bd9Sstevel@tonic-gate }
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate /*
1299*7c478bd9Sstevel@tonic-gate  * add in a given value
1300*7c478bd9Sstevel@tonic-gate  *
1301*7c478bd9Sstevel@tonic-gate  *	on overflow, bit vector will hold least significant BITV_MAX_BYTES,
1302*7c478bd9Sstevel@tonic-gate  *	return value will be -1, and errno will be ERANGE.  otherwise
1303*7c478bd9Sstevel@tonic-gate  *	return is zero and bit vector holds the sum.
1304*7c478bd9Sstevel@tonic-gate  */
1305*7c478bd9Sstevel@tonic-gate static int
bitv_add(bitv * bv,unsigned long long val)1306*7c478bd9Sstevel@tonic-gate bitv_add(bitv *bv, unsigned long long val)
1307*7c478bd9Sstevel@tonic-gate {
1308*7c478bd9Sstevel@tonic-gate 	int cf = 0;	/* carry flag */
1309*7c478bd9Sstevel@tonic-gate 	unsigned short result;
1310*7c478bd9Sstevel@tonic-gate 	int i;
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < BITV_MAX_BYTES; i++) {
1313*7c478bd9Sstevel@tonic-gate 		if (i < sizeof (val))
1314*7c478bd9Sstevel@tonic-gate 			result = cf + bv->v[i] + ((val >> (i * 8)) & 0xff);
1315*7c478bd9Sstevel@tonic-gate 		else
1316*7c478bd9Sstevel@tonic-gate 			result = cf + bv->v[i];
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 		cf = (result >> 8) & 1;
1319*7c478bd9Sstevel@tonic-gate 		bv->v[i] = result & 0xff;
1320*7c478bd9Sstevel@tonic-gate 	}
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate 	if (cf) {
1323*7c478bd9Sstevel@tonic-gate 		errno = ERANGE;
1324*7c478bd9Sstevel@tonic-gate 		return (-1);
1325*7c478bd9Sstevel@tonic-gate 	}
1326*7c478bd9Sstevel@tonic-gate 	return (0);
1327*7c478bd9Sstevel@tonic-gate }
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate /*
1330*7c478bd9Sstevel@tonic-gate  * subtract out a given value
1331*7c478bd9Sstevel@tonic-gate  *
1332*7c478bd9Sstevel@tonic-gate  *	on underflow, bit vector will hold least significant BITV_MAX_BYTES,
1333*7c478bd9Sstevel@tonic-gate  *	return value will be -1, and errno will be ERANGE.  otherwise
1334*7c478bd9Sstevel@tonic-gate  *	return is zero and bit vector holds the difference.
1335*7c478bd9Sstevel@tonic-gate  */
1336*7c478bd9Sstevel@tonic-gate static int
bitv_sub(bitv * bv,unsigned long long val)1337*7c478bd9Sstevel@tonic-gate bitv_sub(bitv *bv, unsigned long long val)
1338*7c478bd9Sstevel@tonic-gate {
1339*7c478bd9Sstevel@tonic-gate 	int bf = 0;	/* borrow flag */
1340*7c478bd9Sstevel@tonic-gate 	unsigned short minuend;
1341*7c478bd9Sstevel@tonic-gate 	unsigned short subtrahend;
1342*7c478bd9Sstevel@tonic-gate 	int i;
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < BITV_MAX_BYTES; i++) {
1345*7c478bd9Sstevel@tonic-gate 		minuend = bv->v[i];
1346*7c478bd9Sstevel@tonic-gate 		if (i < sizeof (val))
1347*7c478bd9Sstevel@tonic-gate 			subtrahend = bf + ((val >> (i * 8)) & 0xff);
1348*7c478bd9Sstevel@tonic-gate 		else
1349*7c478bd9Sstevel@tonic-gate 			subtrahend = bf;
1350*7c478bd9Sstevel@tonic-gate 		if (subtrahend > minuend) {
1351*7c478bd9Sstevel@tonic-gate 			bf = 1;
1352*7c478bd9Sstevel@tonic-gate 			minuend += 1 << 8;
1353*7c478bd9Sstevel@tonic-gate 		} else
1354*7c478bd9Sstevel@tonic-gate 			bf = 0;
1355*7c478bd9Sstevel@tonic-gate 
1356*7c478bd9Sstevel@tonic-gate 		bv->v[i] = minuend - subtrahend;
1357*7c478bd9Sstevel@tonic-gate 	}
1358*7c478bd9Sstevel@tonic-gate 
1359*7c478bd9Sstevel@tonic-gate 	if (bf) {
1360*7c478bd9Sstevel@tonic-gate 		errno = ERANGE;
1361*7c478bd9Sstevel@tonic-gate 		return (-1);
1362*7c478bd9Sstevel@tonic-gate 	}
1363*7c478bd9Sstevel@tonic-gate 	return (0);
1364*7c478bd9Sstevel@tonic-gate }
1365*7c478bd9Sstevel@tonic-gate 
1366*7c478bd9Sstevel@tonic-gate /*
1367*7c478bd9Sstevel@tonic-gate  * see if bv is greater than or equal to a given value
1368*7c478bd9Sstevel@tonic-gate  */
1369*7c478bd9Sstevel@tonic-gate static int
bitv_ge(const bitv * bv,unsigned long long val)1370*7c478bd9Sstevel@tonic-gate bitv_ge(const bitv *bv, unsigned long long val)
1371*7c478bd9Sstevel@tonic-gate {
1372*7c478bd9Sstevel@tonic-gate 	int bf = 0;	/* borrow flag */
1373*7c478bd9Sstevel@tonic-gate 	unsigned short minuend;
1374*7c478bd9Sstevel@tonic-gate 	unsigned short subtrahend;
1375*7c478bd9Sstevel@tonic-gate 	int i;
1376*7c478bd9Sstevel@tonic-gate 
1377*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < BITV_MAX_BYTES; i++) {
1378*7c478bd9Sstevel@tonic-gate 		minuend = bv->v[i];
1379*7c478bd9Sstevel@tonic-gate 		if (i < sizeof (val))
1380*7c478bd9Sstevel@tonic-gate 			subtrahend = bf + ((val >> (i * 8)) & 0xff);
1381*7c478bd9Sstevel@tonic-gate 		else
1382*7c478bd9Sstevel@tonic-gate 			subtrahend = bf;
1383*7c478bd9Sstevel@tonic-gate 		if (subtrahend > minuend)
1384*7c478bd9Sstevel@tonic-gate 			bf = 1;
1385*7c478bd9Sstevel@tonic-gate 		else
1386*7c478bd9Sstevel@tonic-gate 			bf = 0;
1387*7c478bd9Sstevel@tonic-gate 	}
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate 	return (!bf);
1390*7c478bd9Sstevel@tonic-gate }
1391*7c478bd9Sstevel@tonic-gate 
1392*7c478bd9Sstevel@tonic-gate /* parse a string into bit vector, honor leading 0/0x for octal/hex */
1393*7c478bd9Sstevel@tonic-gate static bitv *
bitv_strparse(const char * s,int bits)1394*7c478bd9Sstevel@tonic-gate bitv_strparse(const char *s, int bits)
1395*7c478bd9Sstevel@tonic-gate {
1396*7c478bd9Sstevel@tonic-gate 	unsigned long long base = 10;
1397*7c478bd9Sstevel@tonic-gate 	unsigned long long val;
1398*7c478bd9Sstevel@tonic-gate 	bitv *bv = bitv_alloc();
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 	if (bv == NULL) {
1401*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
1402*7c478bd9Sstevel@tonic-gate 		return (NULL);
1403*7c478bd9Sstevel@tonic-gate 	}
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate 	if (*s == '0') {
1406*7c478bd9Sstevel@tonic-gate 		s++;
1407*7c478bd9Sstevel@tonic-gate 		if (*s == 'x') {
1408*7c478bd9Sstevel@tonic-gate 			s++;
1409*7c478bd9Sstevel@tonic-gate 			base = 16;
1410*7c478bd9Sstevel@tonic-gate 		} else
1411*7c478bd9Sstevel@tonic-gate 			base = 8;
1412*7c478bd9Sstevel@tonic-gate 	}
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 	while (isxdigit(*s)) {
1415*7c478bd9Sstevel@tonic-gate 		/* isxdigit() let's in too much, depending on base */
1416*7c478bd9Sstevel@tonic-gate 		if (base == 8 && (*s < '0' || *s > '7'))
1417*7c478bd9Sstevel@tonic-gate 			break;
1418*7c478bd9Sstevel@tonic-gate 		else if (base == 10 && !isdigit(*s))
1419*7c478bd9Sstevel@tonic-gate 			break;
1420*7c478bd9Sstevel@tonic-gate 
1421*7c478bd9Sstevel@tonic-gate 		/* convert the digit to binary */
1422*7c478bd9Sstevel@tonic-gate 		if (isdigit(*s))
1423*7c478bd9Sstevel@tonic-gate 			val = *s - '0';
1424*7c478bd9Sstevel@tonic-gate 		else
1425*7c478bd9Sstevel@tonic-gate 			val = tolower(*s) - 'a' + 10;
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 		/*
1428*7c478bd9Sstevel@tonic-gate 		 * multiply our big integer by base,
1429*7c478bd9Sstevel@tonic-gate 		 * add in the most recent digit,
1430*7c478bd9Sstevel@tonic-gate 		 * and check for overflow
1431*7c478bd9Sstevel@tonic-gate 		 */
1432*7c478bd9Sstevel@tonic-gate 		if (bitv_mul(bv, base) < 0 ||
1433*7c478bd9Sstevel@tonic-gate 		    bitv_add(bv, val) < 0 ||
1434*7c478bd9Sstevel@tonic-gate 		    bitv_bits(bv) > bits) {
1435*7c478bd9Sstevel@tonic-gate 			bitv_free(bv);
1436*7c478bd9Sstevel@tonic-gate 			errno = ERANGE;
1437*7c478bd9Sstevel@tonic-gate 			return (NULL);
1438*7c478bd9Sstevel@tonic-gate 		}
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate 		s++;
1441*7c478bd9Sstevel@tonic-gate 	}
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	return (bv);
1444*7c478bd9Sstevel@tonic-gate }
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate /* return 0 if two bit vectors represent the same number */
1447*7c478bd9Sstevel@tonic-gate static int
bitv_cmp(const bitv * bv1,const bitv * bv2)1448*7c478bd9Sstevel@tonic-gate bitv_cmp(const bitv *bv1, const bitv *bv2)
1449*7c478bd9Sstevel@tonic-gate {
1450*7c478bd9Sstevel@tonic-gate 	int i;
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 	for (i = BITV_MAX_BYTES - 1; i >= 0; i--)
1453*7c478bd9Sstevel@tonic-gate 		if (bv1->v[i] < bv2->v[i])
1454*7c478bd9Sstevel@tonic-gate 			return (-1);
1455*7c478bd9Sstevel@tonic-gate 		else if (bv1->v[i] > bv2->v[i])
1456*7c478bd9Sstevel@tonic-gate 			return (1);
1457*7c478bd9Sstevel@tonic-gate 	return (0);
1458*7c478bd9Sstevel@tonic-gate }
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate /* CRC code... */
1462*7c478bd9Sstevel@tonic-gate static unsigned crctab[256] = {
1463*7c478bd9Sstevel@tonic-gate 	0x00000000,
1464*7c478bd9Sstevel@tonic-gate 	0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
1465*7c478bd9Sstevel@tonic-gate 	0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
1466*7c478bd9Sstevel@tonic-gate 	0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
1467*7c478bd9Sstevel@tonic-gate 	0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
1468*7c478bd9Sstevel@tonic-gate 	0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
1469*7c478bd9Sstevel@tonic-gate 	0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
1470*7c478bd9Sstevel@tonic-gate 	0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
1471*7c478bd9Sstevel@tonic-gate 	0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
1472*7c478bd9Sstevel@tonic-gate 	0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
1473*7c478bd9Sstevel@tonic-gate 	0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
1474*7c478bd9Sstevel@tonic-gate 	0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
1475*7c478bd9Sstevel@tonic-gate 	0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
1476*7c478bd9Sstevel@tonic-gate 	0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
1477*7c478bd9Sstevel@tonic-gate 	0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
1478*7c478bd9Sstevel@tonic-gate 	0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
1479*7c478bd9Sstevel@tonic-gate 	0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
1480*7c478bd9Sstevel@tonic-gate 	0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
1481*7c478bd9Sstevel@tonic-gate 	0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
1482*7c478bd9Sstevel@tonic-gate 	0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
1483*7c478bd9Sstevel@tonic-gate 	0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
1484*7c478bd9Sstevel@tonic-gate 	0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
1485*7c478bd9Sstevel@tonic-gate 	0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
1486*7c478bd9Sstevel@tonic-gate 	0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
1487*7c478bd9Sstevel@tonic-gate 	0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
1488*7c478bd9Sstevel@tonic-gate 	0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
1489*7c478bd9Sstevel@tonic-gate 	0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
1490*7c478bd9Sstevel@tonic-gate 	0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
1491*7c478bd9Sstevel@tonic-gate 	0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
1492*7c478bd9Sstevel@tonic-gate 	0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
1493*7c478bd9Sstevel@tonic-gate 	0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
1494*7c478bd9Sstevel@tonic-gate 	0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
1495*7c478bd9Sstevel@tonic-gate 	0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
1496*7c478bd9Sstevel@tonic-gate 	0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
1497*7c478bd9Sstevel@tonic-gate 	0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
1498*7c478bd9Sstevel@tonic-gate 	0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
1499*7c478bd9Sstevel@tonic-gate 	0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
1500*7c478bd9Sstevel@tonic-gate 	0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
1501*7c478bd9Sstevel@tonic-gate 	0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
1502*7c478bd9Sstevel@tonic-gate 	0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
1503*7c478bd9Sstevel@tonic-gate 	0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
1504*7c478bd9Sstevel@tonic-gate 	0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
1505*7c478bd9Sstevel@tonic-gate 	0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
1506*7c478bd9Sstevel@tonic-gate 	0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
1507*7c478bd9Sstevel@tonic-gate 	0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
1508*7c478bd9Sstevel@tonic-gate 	0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
1509*7c478bd9Sstevel@tonic-gate 	0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
1510*7c478bd9Sstevel@tonic-gate 	0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
1511*7c478bd9Sstevel@tonic-gate 	0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
1512*7c478bd9Sstevel@tonic-gate 	0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
1513*7c478bd9Sstevel@tonic-gate 	0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
1514*7c478bd9Sstevel@tonic-gate 	0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
1515*7c478bd9Sstevel@tonic-gate };
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate static void
crc(unsigned long * crcp,unsigned val)1518*7c478bd9Sstevel@tonic-gate crc(unsigned long *crcp, unsigned val)
1519*7c478bd9Sstevel@tonic-gate {
1520*7c478bd9Sstevel@tonic-gate 	*crcp = (*crcp<<8) ^ crctab[(unsigned char)((*crcp>>24)^val)];
1521*7c478bd9Sstevel@tonic-gate }
1522