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