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