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