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