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 * 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 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 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 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 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 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 * 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 * 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 * 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 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 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 * 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 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 * 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 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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