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 *
fm_dc_opendict(int version,const char * dirpath,const char * dictname)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
fm_dc_closedict(fm_dc_handle_t * dhp)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
fm_dc_codelen(fm_dc_handle_t * dhp)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
fm_dc_maxkey(fm_dc_handle_t * dhp)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
fm_dc_key2code(fm_dc_handle_t * dhp,const char * key[],char * code,size_t maxcode)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
fm_dc_code2key(fm_dc_handle_t * dhp,const char * code,char * key[],int maxkey)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 *
fm_dc_getprop(fm_dc_handle_t * dhp,const char * name)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 *
dictval2info(const bitv * bv)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 *
numx2info(int numx)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
mycmp(const void * a,const void * b)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
sortkey(const char * key[])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 *
keymatch(const char * linebuf,const char * key[])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
buildcode(fm_dc_handle_t * dhp,const char * rhsp,char * code,size_t maxcode,char * debugstr)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 *
code2dictval(fm_dc_handle_t * dhp,const char * code)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
startparse(struct parsestate * ps,char * ptr)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 *
nextlhs(struct parsestate * ps)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 *
nextrhs(struct parsestate * ps)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 *
bitv_alloc(void)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
bitv_free(bitv * bv)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
bitv_shift(bitv * bv,unsigned bits)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
bitv_setlo(bitv * bv,unsigned bits,unsigned val)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
bitv_shiftin(bitv * bv,unsigned bits,unsigned val)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
bitv_shiftinv(bitv * bv,unsigned bits,const bitv * inbv)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
bitv_bits(const bitv * bv)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
bitv_chunk(const bitv * bv,unsigned limbit,unsigned lobit)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
bitv_mul(bitv * bv,unsigned long long val)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
bitv_add(bitv * bv,unsigned long long val)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
bitv_sub(bitv * bv,unsigned long long val)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
bitv_ge(const bitv * bv,unsigned long long val)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 *
bitv_strparse(const char * s,int bits)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
bitv_cmp(const bitv * bv1,const bitv * bv2)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
crc(unsigned long * crcp,unsigned val)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