#include "util.h" #include "coretype.h" /*****************************************************************************/ /* MODULE NAME: BitVector.c MODULE TYPE: (adt) */ /*****************************************************************************/ /* MODULE IMPORTS: */ /*****************************************************************************/ #include /* MODULE TYPE: (sys) */ #include /* MODULE TYPE: (sys) */ #include /* MODULE TYPE: (sys) */ /*****************************************************************************/ /* MODULE INTERFACE: */ /*****************************************************************************/ #include "bitvect.h" /* ToolBox.h */ #define and && /* logical (boolean) operators: lower case */ #define or || #define not ! #define AND & /* binary (bitwise) operators: UPPER CASE */ #define OR | #define XOR ^ #define NOT ~ #define SHL << #define SHR >> #ifdef ENABLE_MODULO #define mod % /* arithmetic operators */ #endif #define blockdef(name,size) unsigned char name[size] #define blocktypedef(name,size) typedef unsigned char name[size] /*****************************************************************************/ /* MODULE RESOURCES: */ /*****************************************************************************/ #define bits_(BitVector) *(BitVector-3) #define size_(BitVector) *(BitVector-2) #define mask_(BitVector) *(BitVector-1) #define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)" #define ERRCODE_BITS "bits(word) != sizeof(word)*8" #define ERRCODE_WORD "bits(word) < 16" #define ERRCODE_LONG "bits(word) > bits(long)" #define ERRCODE_POWR "bits(word) != 2^x" #define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))" #define ERRCODE_NULL "unable to allocate memory" #define ERRCODE_INDX "index out of range" #define ERRCODE_ORDR "minimum > maximum index" #define ERRCODE_SIZE "bit vector size mismatch" #define ERRCODE_PARS "input string syntax error" #define ERRCODE_OVFL "numeric overflow error" #define ERRCODE_SAME "result vector(s) must be distinct" #define ERRCODE_EXPO "exponent must be positive" #define ERRCODE_ZERO "division by zero error" #define ERRCODE_OOPS "unexpected internal error - please contact author" const N_int BitVector_BYTENORM[256] = { 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */ }; /*****************************************************************************/ /* MODULE IMPLEMENTATION: */ /*****************************************************************************/ /**********************************************/ /* global implementation-intrinsic constants: */ /**********************************************/ #define BIT_VECTOR_HIDDEN_WORDS 3 /*****************************************************************/ /* global machine-dependent constants (set by "BitVector_Boot"): */ /*****************************************************************/ static N_word BITS; /* = # of bits in machine word (must be power of 2) */ static N_word MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */ static N_word LOGBITS; /* = ld(BITS) (logarithmus dualis) */ static N_word FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */ static N_word LSB = 1; /* = mask for least significant bit */ static N_word MSB; /* = mask for most significant bit */ static N_word LONGBITS; /* = # of bits in unsigned long */ static N_word LOG10; /* = logarithm to base 10 of BITS - 1 */ static N_word EXP10; /* = largest possible power of 10 in signed int */ /********************************************************************/ /* global bit mask table for fast access (set by "BitVector_Boot"): */ /********************************************************************/ static wordptr BITMASKTAB; /*****************************/ /* global macro definitions: */ /*****************************/ #define BIT_VECTOR_ZERO_WORDS(target,count) \ while (count-- > 0) *target++ = 0; #define BIT_VECTOR_FILL_WORDS(target,fill,count) \ while (count-- > 0) *target++ = fill; #define BIT_VECTOR_FLIP_WORDS(target,flip,count) \ while (count-- > 0) *target++ ^= flip; #define BIT_VECTOR_COPY_WORDS(target,source,count) \ while (count-- > 0) *target++ = *source++; #define BIT_VECTOR_BACK_WORDS(target,source,count) \ { target += count; source += count; while (count-- > 0) *--target = *--source; } #define BIT_VECTOR_CLR_BIT(address,index) \ *(address+(index>>LOGBITS)) &= NOT BITMASKTAB[index AND MODMASK]; #define BIT_VECTOR_SET_BIT(address,index) \ *(address+(index>>LOGBITS)) |= BITMASKTAB[index AND MODMASK]; #define BIT_VECTOR_TST_BIT(address,index) \ ((*(address+(index>>LOGBITS)) AND BITMASKTAB[index AND MODMASK]) != 0) #define BIT_VECTOR_FLP_BIT(address,index,mask) \ (mask = BITMASKTAB[index AND MODMASK]), \ (((*(addr+(index>>LOGBITS)) ^= mask) AND mask) != 0) #define BIT_VECTOR_DIGITIZE(type,value,digit) \ value = (type) ((digit = value) / 10); \ digit -= value * 10; \ digit += (type) '0'; /*********************************************************/ /* private low-level functions (potentially dangerous!): */ /*********************************************************/ static N_word power10(N_word x) { N_word y = 1; while (x-- > 0) y *= 10; return(y); } static void BIT_VECTOR_zro_words(wordptr addr, N_word count) { BIT_VECTOR_ZERO_WORDS(addr,count) } static void BIT_VECTOR_cpy_words(wordptr target, wordptr source, N_word count) { BIT_VECTOR_COPY_WORDS(target,source,count) } static void BIT_VECTOR_mov_words(wordptr target, wordptr source, N_word count) { if (target != source) { if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count) else BIT_VECTOR_BACK_WORDS(target,source,count) } } static void BIT_VECTOR_ins_words(wordptr addr, N_word total, N_word count, boolean clear) { N_word length; if ((total > 0) and (count > 0)) { if (count > total) count = total; length = total - count; if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length); if (clear) BIT_VECTOR_zro_words(addr,count); } } static void BIT_VECTOR_del_words(wordptr addr, N_word total, N_word count, boolean clear) { N_word length; if ((total > 0) and (count > 0)) { if (count > total) count = total; length = total - count; if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length); if (clear) BIT_VECTOR_zro_words(addr+length,count); } } static void BIT_VECTOR_reverse(charptr string, N_word length) { charptr last; N_char temp; if (length > 1) { last = string + length - 1; while (string < last) { temp = *string; *string = *last; *last = temp; string++; last--; } } } static N_word BIT_VECTOR_int2str(charptr string, N_word value) { N_word length; N_word digit; charptr work; work = string; if (value > 0) { length = 0; while (value > 0) { BIT_VECTOR_DIGITIZE(N_word,value,digit) *work++ = (N_char) digit; length++; } BIT_VECTOR_reverse(string,length); } else { length = 1; *work++ = (N_char) '0'; } return(length); } static N_word BIT_VECTOR_str2int(charptr string, N_word *value) { N_word length; N_word digit; *value = 0; length = 0; digit = (N_word) *string++; /* separate because isdigit() is likely a macro! */ while (isdigit((int)digit) != 0) { length++; digit -= (N_word) '0'; if (*value) *value *= 10; *value += digit; digit = (N_word) *string++; } return(length); } /********************************************/ /* routine to convert error code to string: */ /********************************************/ const char * BitVector_Error(ErrCode error) { switch (error) { case ErrCode_Ok: return( NULL ); break; case ErrCode_Type: return( ERRCODE_TYPE ); break; case ErrCode_Bits: return( ERRCODE_BITS ); break; case ErrCode_Word: return( ERRCODE_WORD ); break; case ErrCode_Long: return( ERRCODE_LONG ); break; case ErrCode_Powr: return( ERRCODE_POWR ); break; case ErrCode_Loga: return( ERRCODE_LOGA ); break; case ErrCode_Null: return( ERRCODE_NULL ); break; case ErrCode_Indx: return( ERRCODE_INDX ); break; case ErrCode_Ordr: return( ERRCODE_ORDR ); break; case ErrCode_Size: return( ERRCODE_SIZE ); break; case ErrCode_Pars: return( ERRCODE_PARS ); break; case ErrCode_Ovfl: return( ERRCODE_OVFL ); break; case ErrCode_Same: return( ERRCODE_SAME ); break; case ErrCode_Expo: return( ERRCODE_EXPO ); break; case ErrCode_Zero: return( ERRCODE_ZERO ); break; default: return( ERRCODE_OOPS ); break; } } /*****************************************/ /* automatic self-configuration routine: */ /*****************************************/ /*******************************************************/ /* */ /* MUST be called once prior to any other function */ /* to initialize the machine dependent constants */ /* of this package! (But call only ONCE, or you */ /* will suffer memory leaks!) */ /* */ /*******************************************************/ ErrCode BitVector_Boot(void) { N_long longsample = 1L; N_word sample = LSB; N_word lsb; if (sizeof(N_word) > sizeof(size_t)) return(ErrCode_Type); BITS = 1; while (sample <<= 1) BITS++; /* determine # of bits in a machine word */ if (BITS != (sizeof(N_word) << 3)) return(ErrCode_Bits); if (BITS < 16) return(ErrCode_Word); LONGBITS = 1; while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */ if (BITS > LONGBITS) return(ErrCode_Long); LOGBITS = 0; sample = BITS; lsb = (sample AND LSB); while ((sample >>= 1) and (not lsb)) { LOGBITS++; lsb = (sample AND LSB); } if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */ if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga); MODMASK = BITS - 1; FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */ MSB = (LSB << MODMASK); BITMASKTAB = (wordptr) yasm_xmalloc((size_t) (BITS << FACTOR)); if (BITMASKTAB == NULL) return(ErrCode_Null); for ( sample = 0; sample < BITS; sample++ ) { BITMASKTAB[sample] = (LSB << sample); } LOG10 = (N_word) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */ EXP10 = power10(LOG10); return(ErrCode_Ok); } void BitVector_Shutdown(void) { if (BITMASKTAB) yasm_xfree(BITMASKTAB); } N_word BitVector_Size(N_int bits) /* bit vector size (# of words) */ { N_word size; size = bits >> LOGBITS; if (bits AND MODMASK) size++; return(size); } N_word BitVector_Mask(N_int bits) /* bit vector mask (unused bits) */ { N_word mask; mask = bits AND MODMASK; if (mask) mask = (N_word) ~(~0L << mask); else mask = (N_word) ~0L; return(mask); } const char * BitVector_Version(void) { return("6.4"); } N_int BitVector_Word_Bits(void) { return(BITS); } N_int BitVector_Long_Bits(void) { return(LONGBITS); } /********************************************************************/ /* */ /* WARNING: Do not "free()" constant character strings, i.e., */ /* don't call "BitVector_Dispose()" for strings returned */ /* by "BitVector_Error()" or "BitVector_Version()"! */ /* */ /* ONLY call this function for strings allocated with "malloc()", */ /* i.e., the strings returned by the functions "BitVector_to_*()" */ /* and "BitVector_Block_Read()"! */ /* */ /********************************************************************/ void BitVector_Dispose(charptr string) /* free string */ { if (string != NULL) yasm_xfree((voidptr) string); } void BitVector_Destroy(wordptr addr) /* free bitvec */ { if (addr != NULL) { addr -= BIT_VECTOR_HIDDEN_WORDS; yasm_xfree((voidptr) addr); } } void BitVector_Destroy_List(listptr list, N_int count) /* free list */ { listptr slot; if (list != NULL) { slot = list; while (count-- > 0) { BitVector_Destroy(*slot++); } free((voidptr) list); } } wordptr BitVector_Create(N_int bits, boolean clear) /* malloc */ { N_word size; N_word mask; N_word bytes; wordptr addr; wordptr zero; size = BitVector_Size(bits); mask = BitVector_Mask(bits); bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; addr = (wordptr) yasm_xmalloc((size_t) bytes); if (addr != NULL) { *addr++ = bits; *addr++ = size; *addr++ = mask; if (clear) { zero = addr; BIT_VECTOR_ZERO_WORDS(zero,size) } } return(addr); } listptr BitVector_Create_List(N_int bits, boolean clear, N_int count) { listptr list = NULL; listptr slot; wordptr addr; N_int i; if (count > 0) { list = (listptr) malloc(sizeof(wordptr) * count); if (list != NULL) { slot = list; for ( i = 0; i < count; i++ ) { addr = BitVector_Create(bits,clear); if (addr == NULL) { BitVector_Destroy_List(list,i); return(NULL); } *slot++ = addr; } } } return(list); } wordptr BitVector_Resize(wordptr oldaddr, N_int bits) /* realloc */ { N_word bytes; N_word oldsize; N_word oldmask; N_word newsize; N_word newmask; wordptr newaddr; wordptr source; wordptr target; oldsize = size_(oldaddr); oldmask = mask_(oldaddr); newsize = BitVector_Size(bits); newmask = BitVector_Mask(bits); if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask; if (newsize <= oldsize) { newaddr = oldaddr; bits_(newaddr) = bits; size_(newaddr) = newsize; mask_(newaddr) = newmask; if (newsize > 0) *(newaddr+newsize-1) &= newmask; } else { bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; newaddr = (wordptr) yasm_xmalloc((size_t) bytes); if (newaddr != NULL) { *newaddr++ = bits; *newaddr++ = newsize; *newaddr++ = newmask; target = newaddr; source = oldaddr; newsize -= oldsize; BIT_VECTOR_COPY_WORDS(target,source,oldsize) BIT_VECTOR_ZERO_WORDS(target,newsize) } BitVector_Destroy(oldaddr); } return(newaddr); } wordptr BitVector_Shadow(wordptr addr) /* makes new, same size but empty */ { return( BitVector_Create(bits_(addr),true) ); } wordptr BitVector_Clone(wordptr addr) /* makes exact duplicate */ { N_word bits; wordptr twin; bits = bits_(addr); twin = BitVector_Create(bits,false); if ((twin != NULL) and (bits > 0)) BIT_VECTOR_cpy_words(twin,addr,size_(addr)); return(twin); } wordptr BitVector_Concat(wordptr X, wordptr Y) /* returns concatenation */ { /* BEWARE that X = most significant part, Y = least significant part! */ N_word bitsX; N_word bitsY; N_word bitsZ; wordptr Z; bitsX = bits_(X); bitsY = bits_(Y); bitsZ = bitsX + bitsY; Z = BitVector_Create(bitsZ,false); if ((Z != NULL) and (bitsZ > 0)) { BIT_VECTOR_cpy_words(Z,Y,size_(Y)); BitVector_Interval_Copy(Z,X,bitsY,0,bitsX); *(Z+size_(Z)-1) &= mask_(Z); } return(Z); } void BitVector_Copy(wordptr X, wordptr Y) /* X = Y */ { N_word sizeX = size_(X); N_word sizeY = size_(Y); N_word maskX = mask_(X); N_word maskY = mask_(Y); N_word fill = 0; wordptr lastX; wordptr lastY; if ((X != Y) and (sizeX > 0)) { lastX = X + sizeX - 1; if (sizeY > 0) { lastY = Y + sizeY - 1; if ( (*lastY AND (maskY AND NOT (maskY >> 1))) == 0 ) *lastY &= maskY; else { fill = (N_word) ~0L; *lastY |= NOT maskY; } while ((sizeX > 0) and (sizeY > 0)) { *X++ = *Y++; sizeX--; sizeY--; } *lastY &= maskY; } while (sizeX-- > 0) *X++ = fill; *lastX &= maskX; } } void BitVector_Empty(wordptr addr) /* X = {} clr all */ { N_word size = size_(addr); BIT_VECTOR_ZERO_WORDS(addr,size) } void BitVector_Fill(wordptr addr) /* X = ~{} set all */ { N_word size = size_(addr); N_word mask = mask_(addr); N_word fill = (N_word) ~0L; if (size > 0) { BIT_VECTOR_FILL_WORDS(addr,fill,size) *(--addr) &= mask; } } void BitVector_Flip(wordptr addr) /* X = ~X flip all */ { N_word size = size_(addr); N_word mask = mask_(addr); N_word flip = (N_word) ~0L; if (size > 0) { BIT_VECTOR_FLIP_WORDS(addr,flip,size) *(--addr) &= mask; } } void BitVector_Primes(wordptr addr) { N_word bits = bits_(addr); N_word size = size_(addr); wordptr work; N_word temp; N_word i,j; if (size > 0) { temp = 0xAAAA; i = BITS >> 4; while (--i > 0) { temp <<= 16; temp |= 0xAAAA; } i = size; work = addr; *work++ = temp XOR 0x0006; while (--i > 0) *work++ = temp; for ( i = 3; (j = i * i) < bits; i += 2 ) { for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j) } *(addr+size-1) &= mask_(addr); } } void BitVector_Reverse(wordptr X, wordptr Y) { N_word bits = bits_(X); N_word mask; N_word bit; N_word value; if (bits > 0) { if (X == Y) BitVector_Interval_Reverse(X,0,bits-1); else if (bits == bits_(Y)) { /* mask = mask_(Y); */ /* mask &= NOT (mask >> 1); */ mask = BITMASKTAB[(bits-1) AND MODMASK]; Y += size_(Y) - 1; value = 0; bit = LSB; while (bits-- > 0) { if ((*Y AND mask) != 0) { value |= bit; } if (not (mask >>= 1)) { Y--; mask = MSB; } if (not (bit <<= 1)) { *X++ = value; value = 0; bit = LSB; } } if (bit > LSB) *X = value; } } } void BitVector_Interval_Empty(wordptr addr, N_int lower, N_int upper) { /* X = X \ [lower..upper] */ N_word bits = bits_(addr); N_word size = size_(addr); wordptr loaddr; wordptr hiaddr; N_word lobase; N_word hibase; N_word lomask; N_word himask; N_word diff; if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) { lobase = lower >> LOGBITS; hibase = upper >> LOGBITS; diff = hibase - lobase; loaddr = addr + lobase; hiaddr = addr + hibase; lomask = (N_word) (~0L << (lower AND MODMASK)); himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); if (diff == 0) { *loaddr &= NOT (lomask AND himask); } else { *loaddr++ &= NOT lomask; while (--diff > 0) { *loaddr++ = 0; } *hiaddr &= NOT himask; } } } void BitVector_Interval_Fill(wordptr addr, N_int lower, N_int upper) { /* X = X + [lower..upper] */ N_word bits = bits_(addr); N_word size = size_(addr); N_word fill = (N_word) ~0L; wordptr loaddr; wordptr hiaddr; N_word lobase; N_word hibase; N_word lomask; N_word himask; N_word diff; if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) { lobase = lower >> LOGBITS; hibase = upper >> LOGBITS; diff = hibase - lobase; loaddr = addr + lobase; hiaddr = addr + hibase; lomask = (N_word) (~0L << (lower AND MODMASK)); himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); if (diff == 0) { *loaddr |= (lomask AND himask); } else { *loaddr++ |= lomask; while (--diff > 0) { *loaddr++ = fill; } *hiaddr |= himask; } *(addr+size-1) &= mask_(addr); } } void BitVector_Interval_Flip(wordptr addr, N_int lower, N_int upper) { /* X = X ^ [lower..upper] */ N_word bits = bits_(addr); N_word size = size_(addr); N_word flip = (N_word) ~0L; wordptr loaddr; wordptr hiaddr; N_word lobase; N_word hibase; N_word lomask; N_word himask; N_word diff; if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper)) { lobase = lower >> LOGBITS; hibase = upper >> LOGBITS; diff = hibase - lobase; loaddr = addr + lobase; hiaddr = addr + hibase; lomask = (N_word) (~0L << (lower AND MODMASK)); himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1); if (diff == 0) { *loaddr ^= (lomask AND himask); } else { *loaddr++ ^= lomask; while (--diff > 0) { *loaddr++ ^= flip; } *hiaddr ^= himask; } *(addr+size-1) &= mask_(addr); } } void BitVector_Interval_Reverse(wordptr addr, N_int lower, N_int upper) { N_word bits = bits_(addr); wordptr loaddr; wordptr hiaddr; N_word lomask; N_word himask; if ((bits > 0) and (lower < bits) and (upper < bits) and (lower < upper)) { loaddr = addr + (lower >> LOGBITS); hiaddr = addr + (upper >> LOGBITS); lomask = BITMASKTAB[lower AND MODMASK]; himask = BITMASKTAB[upper AND MODMASK]; for ( bits = upper - lower + 1; bits > 1; bits -= 2 ) { if (((*loaddr AND lomask) != 0) XOR ((*hiaddr AND himask) != 0)) { *loaddr ^= lomask; /* swap bits only if they differ! */ *hiaddr ^= himask; } if (not (lomask <<= 1)) { lomask = LSB; loaddr++; } if (not (himask >>= 1)) { himask = MSB; hiaddr--; } } } } boolean BitVector_interval_scan_inc(wordptr addr, N_int start, N_intptr min, N_intptr max) { N_word size = size_(addr); N_word mask = mask_(addr); N_word offset; N_word bitmask; N_word value; boolean empty; if ((size == 0) or (start >= bits_(addr))) return(FALSE); *min = start; *max = start; offset = start >> LOGBITS; *(addr+size-1) &= mask; addr += offset; size -= offset; bitmask = BITMASKTAB[start AND MODMASK]; mask = NOT (bitmask OR (bitmask - 1)); value = *addr++; if ((value AND bitmask) == 0) { value &= mask; if (value == 0) { offset++; empty = TRUE; while (empty and (--size > 0)) { if ((value = *addr++)) empty = false; else offset++; } if (empty) return(FALSE); } start = offset << LOGBITS; bitmask = LSB; mask = value; while (not (mask AND LSB)) { bitmask <<= 1; mask >>= 1; start++; } mask = NOT (bitmask OR (bitmask - 1)); *min = start; *max = start; } value = NOT value; value &= mask; if (value == 0) { offset++; empty = TRUE; while (empty and (--size > 0)) { if ((value = NOT *addr++)) empty = false; else offset++; } if (empty) value = LSB; } start = offset << LOGBITS; while (not (value AND LSB)) { value >>= 1; start++; } *max = --start; return(TRUE); } boolean BitVector_interval_scan_dec(wordptr addr, N_int start, N_intptr min, N_intptr max) { N_word size = size_(addr); N_word mask = mask_(addr); N_word offset; N_word bitmask; N_word value; boolean empty; if ((size == 0) or (start >= bits_(addr))) return(FALSE); *min = start; *max = start; offset = start >> LOGBITS; if (offset >= size) return(FALSE); *(addr+size-1) &= mask; addr += offset; size = ++offset; bitmask = BITMASKTAB[start AND MODMASK]; mask = (bitmask - 1); value = *addr--; if ((value AND bitmask) == 0) { value &= mask; if (value == 0) { offset--; empty = TRUE; while (empty and (--size > 0)) { if ((value = *addr--)) empty = false; else offset--; } if (empty) return(FALSE); } start = offset << LOGBITS; bitmask = MSB; mask = value; while (not (mask AND MSB)) { bitmask >>= 1; mask <<= 1; start--; } mask = (bitmask - 1); *max = --start; *min = start; } value = NOT value; value &= mask; if (value == 0) { offset--; empty = TRUE; while (empty and (--size > 0)) { if ((value = NOT *addr--)) empty = false; else offset--; } if (empty) value = MSB; } start = offset << LOGBITS; while (not (value AND MSB)) { value <<= 1; start--; } *min = start; return(TRUE); } void BitVector_Interval_Copy(wordptr X, wordptr Y, N_int Xoffset, N_int Yoffset, N_int length) { N_word bitsX = bits_(X); N_word bitsY = bits_(Y); N_word source = 0; /* silence compiler warning */ N_word target = 0; /* silence compiler warning */ N_word s_lo_base; N_word s_hi_base; N_word s_lo_bit; N_word s_hi_bit; N_word s_base; N_word s_lower = 0; /* silence compiler warning */ N_word s_upper = 0; /* silence compiler warning */ N_word s_bits; N_word s_min; N_word s_max; N_word t_lo_base; N_word t_hi_base; N_word t_lo_bit; N_word t_hi_bit; N_word t_base; N_word t_lower = 0; /* silence compiler warning */ N_word t_upper = 0; /* silence compiler warning */ N_word t_bits; N_word t_min; N_word mask; N_word bits; N_word sel; boolean ascending; boolean notfirst; wordptr Z = X; if ((length > 0) and (Xoffset < bitsX) and (Yoffset < bitsY)) { if ((Xoffset + length) > bitsX) length = bitsX - Xoffset; if ((Yoffset + length) > bitsY) length = bitsY - Yoffset; ascending = (Xoffset <= Yoffset); s_lo_base = Yoffset >> LOGBITS; s_lo_bit = Yoffset AND MODMASK; Yoffset += --length; s_hi_base = Yoffset >> LOGBITS; s_hi_bit = Yoffset AND MODMASK; t_lo_base = Xoffset >> LOGBITS; t_lo_bit = Xoffset AND MODMASK; Xoffset += length; t_hi_base = Xoffset >> LOGBITS; t_hi_bit = Xoffset AND MODMASK; if (ascending) { s_base = s_lo_base; t_base = t_lo_base; } else { s_base = s_hi_base; t_base = t_hi_base; } s_bits = 0; t_bits = 0; Y += s_base; X += t_base; notfirst = FALSE; while (TRUE) { if (t_bits == 0) { if (notfirst) { *X = target; if (ascending) { if (t_base == t_hi_base) break; t_base++; X++; } else { if (t_base == t_lo_base) break; t_base--; X--; } } sel = ((t_base == t_hi_base) << 1) OR (t_base == t_lo_base); switch (sel) { case 0: t_lower = 0; t_upper = BITS - 1; t_bits = BITS; target = 0; break; case 1: t_lower = t_lo_bit; t_upper = BITS - 1; t_bits = BITS - t_lo_bit; mask = (N_word) (~0L << t_lower); target = *X AND NOT mask; break; case 2: t_lower = 0; t_upper = t_hi_bit; t_bits = t_hi_bit + 1; mask = (N_word) ((~0L << t_upper) << 1); target = *X AND mask; break; case 3: t_lower = t_lo_bit; t_upper = t_hi_bit; t_bits = t_hi_bit - t_lo_bit + 1; mask = (N_word) (~0L << t_lower); mask &= (N_word) ~((~0L << t_upper) << 1); target = *X AND NOT mask; break; } } if (s_bits == 0) { if (notfirst) { if (ascending) { if (s_base == s_hi_base) break; s_base++; Y++; } else { if (s_base == s_lo_base) break; s_base--; Y--; } } source = *Y; sel = ((s_base == s_hi_base) << 1) OR (s_base == s_lo_base); switch (sel) { case 0: s_lower = 0; s_upper = BITS - 1; s_bits = BITS; break; case 1: s_lower = s_lo_bit; s_upper = BITS - 1; s_bits = BITS - s_lo_bit; break; case 2: s_lower = 0; s_upper = s_hi_bit; s_bits = s_hi_bit + 1; break; case 3: s_lower = s_lo_bit; s_upper = s_hi_bit; s_bits = s_hi_bit - s_lo_bit + 1; break; } } notfirst = TRUE; if (s_bits > t_bits) { bits = t_bits - 1; if (ascending) { s_min = s_lower; s_max = s_lower + bits; } else { s_max = s_upper; s_min = s_upper - bits; } t_min = t_lower; } else { bits = s_bits - 1; if (ascending) t_min = t_lower; else t_min = t_upper - bits; s_min = s_lower; s_max = s_upper; } bits++; mask = (N_word) (~0L << s_min); mask &= (N_word) ~((~0L << s_max) << 1); if (s_min == t_min) target |= (source AND mask); else { if (s_min < t_min) target |= (source AND mask) << (t_min-s_min); else target |= (source AND mask) >> (s_min-t_min); } if (ascending) { s_lower += bits; t_lower += bits; } else { s_upper -= bits; t_upper -= bits; } s_bits -= bits; t_bits -= bits; } *(Z+size_(Z)-1) &= mask_(Z); } } wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y, N_int Xoffset, N_int Xlength, N_int Yoffset, N_int Ylength) { N_word Xbits = bits_(X); N_word Ybits = bits_(Y); N_word limit; N_word diff; if ((Xoffset <= Xbits) and (Yoffset <= Ybits)) { limit = Xoffset + Xlength; if (limit > Xbits) { limit = Xbits; Xlength = Xbits - Xoffset; } if ((Yoffset + Ylength) > Ybits) { Ylength = Ybits - Yoffset; } if (Xlength == Ylength) { if ((Ylength > 0) and ((X != Y) or (Xoffset != Yoffset))) { BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); } } else /* Xlength != Ylength */ { if (Xlength > Ylength) { diff = Xlength - Ylength; if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,FALSE); if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL); } else /* Ylength > Xlength ==> Ylength > 0 */ { diff = Ylength - Xlength; if (X != Y) { if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); if (limit < Xbits) BitVector_Insert(X,limit,diff,FALSE); BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); } else /* in-place */ { if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); if (limit >= Xbits) { BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); } else /* limit < Xbits */ { BitVector_Insert(X,limit,diff,FALSE); if ((Yoffset+Ylength) <= limit) { BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); } else /* overlaps or lies above critical area */ { if (limit <= Yoffset) { Yoffset += diff; BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); } else /* Yoffset < limit */ { Xlength = limit - Yoffset; BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength); Yoffset = Xoffset + Ylength; /* = limit + diff */ Xoffset += Xlength; Ylength -= Xlength; BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); } } } } } } } return(X); } boolean BitVector_is_empty(wordptr addr) /* X == {} ? */ { N_word size = size_(addr); boolean r = TRUE; if (size > 0) { *(addr+size-1) &= mask_(addr); while (r and (size-- > 0)) r = ( *addr++ == 0 ); } return(r); } boolean BitVector_is_full(wordptr addr) /* X == ~{} ? */ { N_word size = size_(addr); N_word mask = mask_(addr); boolean r = FALSE; wordptr last; if (size > 0) { r = TRUE; last = addr + size - 1; *last |= NOT mask; while (r and (size-- > 0)) r = ( NOT *addr++ == 0 ); *last &= mask; } return(r); } boolean BitVector_equal(wordptr X, wordptr Y) /* X == Y ? */ { N_word size = size_(X); N_word mask = mask_(X); boolean r = FALSE; if (bits_(X) == bits_(Y)) { r = TRUE; if (size > 0) { *(X+size-1) &= mask; *(Y+size-1) &= mask; while (r and (size-- > 0)) r = (*X++ == *Y++); } } return(r); } Z_int BitVector_Lexicompare(wordptr X, wordptr Y) /* X <,=,> Y ? */ { /* unsigned */ N_word bitsX = bits_(X); N_word bitsY = bits_(Y); N_word size = size_(X); boolean r = TRUE; if (bitsX == bitsY) { if (size > 0) { X += size; Y += size; while (r and (size-- > 0)) r = (*(--X) == *(--Y)); } if (r) return((Z_int) 0); else { if (*X < *Y) return((Z_int) -1); else return((Z_int) 1); } } else { if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1); } } Z_int BitVector_Compare(wordptr X, wordptr Y) /* X <,=,> Y ? */ { /* signed */ N_word bitsX = bits_(X); N_word bitsY = bits_(Y); N_word size = size_(X); N_word mask = mask_(X); N_word sign; boolean r = TRUE; if (bitsX == bitsY) { if (size > 0) { X += size; Y += size; mask &= NOT (mask >> 1); if ((sign = (*(X-1) AND mask)) != (*(Y-1) AND mask)) { if (sign) return((Z_int) -1); else return((Z_int) 1); } while (r and (size-- > 0)) r = (*(--X) == *(--Y)); } if (r) return((Z_int) 0); else { if (*X < *Y) return((Z_int) -1); else return((Z_int) 1); } } else { if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1); } } charptr BitVector_to_Hex(wordptr addr) { N_word bits = bits_(addr); N_word size = size_(addr); N_word value; N_word count; N_word digit; N_word length; charptr string; length = bits >> 2; if (bits AND 0x0003) length++; string = (charptr) yasm_xmalloc((size_t) (length+1)); if (string == NULL) return(NULL); string += length; *string = (N_char) '\0'; if (size > 0) { *(addr+size-1) &= mask_(addr); while ((size-- > 0) and (length > 0)) { value = *addr++; count = BITS >> 2; while ((count-- > 0) and (length > 0)) { digit = value AND 0x000F; if (digit > 9) digit += (N_word) 'A' - 10; else digit += (N_word) '0'; *(--string) = (N_char) digit; length--; if ((count > 0) and (length > 0)) value >>= 4; } } } return(string); } ErrCode BitVector_from_Hex(wordptr addr, charptr string) { N_word size = size_(addr); N_word mask = mask_(addr); boolean ok = TRUE; size_t length; N_word value; N_word count; int digit; if (size > 0) { length = strlen((char *) string); string += length; while (size-- > 0) { value = 0; for ( count = 0; (ok and (length > 0) and (count < BITS)); count += 4 ) { digit = (int) *(--string); length--; /* separate because toupper() is likely a macro! */ digit = toupper(digit); if (digit == '_') count -= 4; else if ((ok = (isxdigit(digit) != 0))) { if (digit >= (int) 'A') digit -= (int) 'A' - 10; else digit -= (int) '0'; value |= (((N_word) digit) << count); } } *addr++ = value; } *(--addr) &= mask; } if (ok) return(ErrCode_Ok); else return(ErrCode_Pars); } ErrCode BitVector_from_Oct(wordptr addr, charptr string) { N_word size = size_(addr); N_word mask = mask_(addr); boolean ok = TRUE; size_t length; N_word value; N_word value_fill = 0; N_word count; Z_word count_fill = 0; int digit = 0; if (size > 0) { length = strlen((char *) string); string += length; while (size-- > 0) { value = value_fill; for ( count = count_fill; (ok and (length > 0) and (count < BITS)); count += 3 ) { digit = (int) *(--string); length--; if (digit == '_') count -= 3; else if ((ok = (isdigit(digit) && digit != '8' && digit != '9')) != 0) { digit -= (int) '0'; value |= (((N_word) digit) << count); } } count_fill = (Z_word)count-(Z_word)BITS; if (count_fill > 0) value_fill = (((N_word) digit) >> (3-count_fill)); else value_fill = 0; *addr++ = value; } *(--addr) &= mask; } if (ok) return(ErrCode_Ok); else return(ErrCode_Pars); } charptr BitVector_to_Bin(wordptr addr) { N_word size = size_(addr); N_word value; N_word count; N_word digit; N_word length; charptr string; length = bits_(addr); string = (charptr) yasm_xmalloc((size_t) (length+1)); if (string == NULL) return(NULL); string += length; *string = (N_char) '\0'; if (size > 0) { *(addr+size-1) &= mask_(addr); while (size-- > 0) { value = *addr++; count = BITS; if (count > length) count = length; while (count-- > 0) { digit = value AND 0x0001; digit += (N_word) '0'; *(--string) = (N_char) digit; length--; if (count > 0) value >>= 1; } } } return(string); } ErrCode BitVector_from_Bin(wordptr addr, charptr string) { N_word size = size_(addr); N_word mask = mask_(addr); boolean ok = TRUE; size_t length; N_word value; N_word count; int digit; if (size > 0) { length = strlen((char *) string); string += length; while (size-- > 0) { value = 0; for ( count = 0; (ok and (length > 0) and (count < BITS)); count++ ) { digit = (int) *(--string); length--; switch (digit) { case (int) '0': break; case (int) '1': value |= BITMASKTAB[count]; break; case (int) '_': count--; break; default: ok = FALSE; break; } } *addr++ = value; } *(--addr) &= mask; } if (ok) return(ErrCode_Ok); else return(ErrCode_Pars); } charptr BitVector_to_Dec(wordptr addr) { N_word bits = bits_(addr); N_word length; N_word digits; N_word count; N_word q; N_word r; boolean loop; charptr result; charptr string; wordptr quot; wordptr rest; wordptr temp; wordptr base; Z_int sign; length = (N_word) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */ length += 2; /* compensate for truncating & provide space for minus sign */ result = (charptr) yasm_xmalloc((size_t) (length+1)); /* remember the '\0'! */ if (result == NULL) return(NULL); string = result; sign = BitVector_Sign(addr); if ((bits < 4) or (sign == 0)) { if (bits > 0) digits = *addr; else digits = (N_word) 0; if (sign < 0) digits = ((N_word)(-((Z_word)digits))) AND mask_(addr); *string++ = (N_char) digits + (N_char) '0'; digits = 1; } else { quot = BitVector_Create(bits,FALSE); if (quot == NULL) { BitVector_Dispose(result); return(NULL); } rest = BitVector_Create(bits,FALSE); if (rest == NULL) { BitVector_Dispose(result); BitVector_Destroy(quot); return(NULL); } temp = BitVector_Create(bits,FALSE); if (temp == NULL) { BitVector_Dispose(result); BitVector_Destroy(quot); BitVector_Destroy(rest); return(NULL); } base = BitVector_Create(bits,TRUE); if (base == NULL) { BitVector_Dispose(result); BitVector_Destroy(quot); BitVector_Destroy(rest); BitVector_Destroy(temp); return(NULL); } if (sign < 0) BitVector_Negate(quot,addr); else BitVector_Copy(quot,addr); digits = 0; *base = EXP10; loop = (bits >= BITS); do { if (loop) { BitVector_Copy(temp,quot); if (BitVector_Div_Pos(quot,temp,base,rest)) { BitVector_Dispose(result); /* emergency exit */ BitVector_Destroy(quot); BitVector_Destroy(rest); /* should never occur */ BitVector_Destroy(temp); /* under normal operation */ BitVector_Destroy(base); return(NULL); } loop = not BitVector_is_empty(quot); q = *rest; } else q = *quot; count = LOG10; while (((loop and (count-- > 0)) or ((not loop) and (q != 0))) and (digits < length)) { if (q != 0) { BIT_VECTOR_DIGITIZE(N_word,q,r) } else r = (N_word) '0'; *string++ = (N_char) r; digits++; } } while (loop and (digits < length)); BitVector_Destroy(quot); BitVector_Destroy(rest); BitVector_Destroy(temp); BitVector_Destroy(base); } if ((sign < 0) and (digits < length)) { *string++ = (N_char) '-'; digits++; } *string = (N_char) '\0'; BIT_VECTOR_reverse(result,digits); return(result); } struct BitVector_from_Dec_static_data { wordptr term; wordptr base; wordptr prod; wordptr rank; wordptr temp; }; BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits) { BitVector_from_Dec_static_data *data; data = yasm_xmalloc(sizeof(BitVector_from_Dec_static_data)); if (bits > 0) { data->term = BitVector_Create(BITS,FALSE); data->base = BitVector_Create(BITS,FALSE); data->prod = BitVector_Create(bits,FALSE); data->rank = BitVector_Create(bits,FALSE); data->temp = BitVector_Create(bits,FALSE); } else { data->term = NULL; data->base = NULL; data->prod = NULL; data->rank = NULL; data->temp = NULL; } return data; } void BitVector_from_Dec_static_Shutdown(BitVector_from_Dec_static_data *data) { if (data) { BitVector_Destroy(data->term); BitVector_Destroy(data->base); BitVector_Destroy(data->prod); BitVector_Destroy(data->rank); BitVector_Destroy(data->temp); } yasm_xfree(data); } ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data, wordptr addr, charptr string) { ErrCode error = ErrCode_Ok; N_word bits = bits_(addr); N_word mask = mask_(addr); boolean init = (bits > BITS); boolean minus; boolean shift; boolean carry; wordptr term; wordptr base; wordptr prod; wordptr rank; wordptr temp; N_word accu; N_word powr; N_word count; size_t length; int digit; if (bits > 0) { term = data->term; base = data->base; prod = data->prod; rank = data->rank; temp = data->temp; length = strlen((char *) string); if (length == 0) return(ErrCode_Pars); digit = (int) *string; if ((minus = (digit == (int) '-')) or (digit == (int) '+')) { string++; if (--length == 0) return(ErrCode_Pars); } string += length; if (init) { BitVector_Empty(prod); BitVector_Empty(rank); } BitVector_Empty(addr); *base = EXP10; shift = FALSE; while ((not error) and (length > 0)) { accu = 0; powr = 1; count = LOG10; while ((not error) and (length > 0) and (count-- > 0)) { digit = (int) *(--string); length--; /* separate because isdigit() is likely a macro! */ if (isdigit(digit) != 0) { accu += ((N_word) digit - (N_word) '0') * powr; powr *= 10; } else error = ErrCode_Pars; } if (not error) { if (shift) { *term = accu; BitVector_Copy(temp,rank); error = BitVector_Mul_Pos(prod,temp,term,FALSE); } else { *prod = accu; if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl; } if (not error) { carry = FALSE; BitVector_compute(addr,addr,prod,FALSE,&carry); /* ignores sign change (= overflow) but not */ /* numbers too large (= carry) for resulting bit vector */ if (carry) error = ErrCode_Ovfl; else { if (length > 0) { if (shift) { BitVector_Copy(temp,rank); error = BitVector_Mul_Pos(rank,temp,base,FALSE); } else { *rank = *base; shift = TRUE; } } } } } } if (not error and minus) { BitVector_Negate(addr,addr); if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0) error = ErrCode_Ovfl; } } return(error); } ErrCode BitVector_from_Dec(wordptr addr, charptr string) { ErrCode error = ErrCode_Ok; N_word bits = bits_(addr); N_word mask = mask_(addr); boolean init = (bits > BITS); boolean minus; boolean shift; boolean carry; wordptr term; wordptr base; wordptr prod; wordptr rank; wordptr temp; N_word accu; N_word powr; N_word count; size_t length; int digit; if (bits > 0) { length = strlen((char *) string); if (length == 0) return(ErrCode_Pars); digit = (int) *string; if ((minus = (digit == (int) '-')) or (digit == (int) '+')) { string++; if (--length == 0) return(ErrCode_Pars); } string += length; term = BitVector_Create(BITS,FALSE); if (term == NULL) { return(ErrCode_Null); } base = BitVector_Create(BITS,FALSE); if (base == NULL) { BitVector_Destroy(term); return(ErrCode_Null); } prod = BitVector_Create(bits,init); if (prod == NULL) { BitVector_Destroy(term); BitVector_Destroy(base); return(ErrCode_Null); } rank = BitVector_Create(bits,init); if (rank == NULL) { BitVector_Destroy(term); BitVector_Destroy(base); BitVector_Destroy(prod); return(ErrCode_Null); } temp = BitVector_Create(bits,FALSE); if (temp == NULL) { BitVector_Destroy(term); BitVector_Destroy(base); BitVector_Destroy(prod); BitVector_Destroy(rank); return(ErrCode_Null); } BitVector_Empty(addr); *base = EXP10; shift = FALSE; while ((not error) and (length > 0)) { accu = 0; powr = 1; count = LOG10; while ((not error) and (length > 0) and (count-- > 0)) { digit = (int) *(--string); length--; /* separate because isdigit() is likely a macro! */ if (isdigit(digit) != 0) { accu += ((N_word) digit - (N_word) '0') * powr; powr *= 10; } else error = ErrCode_Pars; } if (not error) { if (shift) { *term = accu; BitVector_Copy(temp,rank); error = BitVector_Mul_Pos(prod,temp,term,FALSE); } else { *prod = accu; if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl; } if (not error) { carry = FALSE; BitVector_compute(addr,addr,prod,FALSE,&carry); /* ignores sign change (= overflow) but not */ /* numbers too large (= carry) for resulting bit vector */ if (carry) error = ErrCode_Ovfl; else { if (length > 0) { if (shift) { BitVector_Copy(temp,rank); error = BitVector_Mul_Pos(rank,temp,base,FALSE); } else { *rank = *base; shift = TRUE; } } } } } } BitVector_Destroy(term); BitVector_Destroy(base); BitVector_Destroy(prod); BitVector_Destroy(rank); BitVector_Destroy(temp); if (not error and minus) { BitVector_Negate(addr,addr); if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0) error = ErrCode_Ovfl; } } return(error); } charptr BitVector_to_Enum(wordptr addr) { N_word bits = bits_(addr); N_word sample; N_word length; N_word digits; N_word factor; N_word power; N_word start; N_word min; N_word max; charptr string; charptr target; boolean comma; if (bits > 0) { sample = bits - 1; /* greatest possible index */ length = 2; /* account for index 0 and terminating '\0' */ digits = 1; /* account for intervening dashes and commas */ factor = 1; power = 10; while (sample >= (power-1)) { length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */ factor = power; power *= 10; } if (sample > --factor) { sample -= factor; factor = (N_word) ( sample / 3 ); factor = (factor << 1) + (sample - (factor * 3)); length += ++digits * factor; } } else length = 1; string = (charptr) yasm_xmalloc((size_t) length); if (string == NULL) return(NULL); start = 0; comma = FALSE; target = string; while ((start < bits) and BitVector_interval_scan_inc(addr,start,&min,&max)) { start = max + 2; if (comma) *target++ = (N_char) ','; if (min == max) { target += BIT_VECTOR_int2str(target,min); } else { if (min+1 == max) { target += BIT_VECTOR_int2str(target,min); *target++ = (N_char) ','; target += BIT_VECTOR_int2str(target,max); } else { target += BIT_VECTOR_int2str(target,min); *target++ = (N_char) '-'; target += BIT_VECTOR_int2str(target,max); } } comma = TRUE; } *target = (N_char) '\0'; return(string); } ErrCode BitVector_from_Enum(wordptr addr, charptr string) { ErrCode error = ErrCode_Ok; N_word bits = bits_(addr); N_word state = 1; N_word token; N_word indx = 0; /* silence compiler warning */ N_word start = 0; /* silence compiler warning */ if (bits > 0) { BitVector_Empty(addr); while ((not error) and (state != 0)) { token = (N_word) *string; /* separate because isdigit() is likely a macro! */ if (isdigit((int)token) != 0) { string += BIT_VECTOR_str2int(string,&indx); if (indx < bits) token = (N_word) '0'; else error = ErrCode_Indx; } else string++; if (not error) switch (state) { case 1: switch (token) { case (N_word) '0': state = 2; break; case (N_word) '\0': state = 0; break; default: error = ErrCode_Pars; break; } break; case 2: switch (token) { case (N_word) '-': start = indx; state = 3; break; case (N_word) ',': BIT_VECTOR_SET_BIT(addr,indx) state = 5; break; case (N_word) '\0': BIT_VECTOR_SET_BIT(addr,indx) state = 0; break; default: error = ErrCode_Pars; break; } break; case 3: switch (token) { case (N_word) '0': if (start < indx) BitVector_Interval_Fill(addr,start,indx); else if (start == indx) BIT_VECTOR_SET_BIT(addr,indx) else error = ErrCode_Ordr; state = 4; break; default: error = ErrCode_Pars; break; } break; case 4: switch (token) { case (N_word) ',': state = 5; break; case (N_word) '\0': state = 0; break; default: error = ErrCode_Pars; break; } break; case 5: switch (token) { case (N_word) '0': state = 2; break; default: error = ErrCode_Pars; break; } break; } } } return(error); } void BitVector_Bit_Off(wordptr addr, N_int indx) /* X = X \ {x} */ { if (indx < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,indx) } void BitVector_Bit_On(wordptr addr, N_int indx) /* X = X + {x} */ { if (indx < bits_(addr)) BIT_VECTOR_SET_BIT(addr,indx) } boolean BitVector_bit_flip(wordptr addr, N_int indx) /* X=(X+{x})\(X*{x}) */ { N_word mask; if (indx < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,indx,mask) ); else return( FALSE ); } boolean BitVector_bit_test(wordptr addr, N_int indx) /* {x} in X ? */ { if (indx < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,indx) ); else return( FALSE ); } void BitVector_Bit_Copy(wordptr addr, N_int indx, boolean bit) { if (indx < bits_(addr)) { if (bit) BIT_VECTOR_SET_BIT(addr,indx) else BIT_VECTOR_CLR_BIT(addr,indx) } } void BitVector_LSB(wordptr addr, boolean bit) { if (bits_(addr) > 0) { if (bit) *addr |= LSB; else *addr &= NOT LSB; } } void BitVector_MSB(wordptr addr, boolean bit) { N_word size = size_(addr); N_word mask = mask_(addr); if (size-- > 0) { if (bit) *(addr+size) |= mask AND NOT (mask >> 1); else *(addr+size) &= NOT mask OR (mask >> 1); } } boolean BitVector_lsb_(wordptr addr) { if (size_(addr) > 0) return( (*addr AND LSB) != 0 ); else return( FALSE ); } boolean BitVector_msb_(wordptr addr) { N_word size = size_(addr); N_word mask = mask_(addr); if (size-- > 0) return( (*(addr+size) AND (mask AND NOT (mask >> 1))) != 0 ); else return( FALSE ); } boolean BitVector_rotate_left(wordptr addr) { N_word size = size_(addr); N_word mask = mask_(addr); N_word msb; boolean carry_in; boolean carry_out = FALSE; if (size > 0) { msb = mask AND NOT (mask >> 1); carry_in = ((*(addr+size-1) AND msb) != 0); while (size-- > 1) { carry_out = ((*addr AND MSB) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; carry_in = carry_out; addr++; } carry_out = ((*addr AND msb) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; *addr &= mask; } return(carry_out); } boolean BitVector_rotate_right(wordptr addr) { N_word size = size_(addr); N_word mask = mask_(addr); N_word msb; boolean carry_in; boolean carry_out = FALSE; if (size > 0) { msb = mask AND NOT (mask >> 1); carry_in = ((*addr AND LSB) != 0); addr += size-1; *addr &= mask; carry_out = ((*addr AND LSB) != 0); *addr >>= 1; if (carry_in) *addr |= msb; carry_in = carry_out; addr--; size--; while (size-- > 0) { carry_out = ((*addr AND LSB) != 0); *addr >>= 1; if (carry_in) *addr |= MSB; carry_in = carry_out; addr--; } } return(carry_out); } boolean BitVector_shift_left(wordptr addr, boolean carry_in) { N_word size = size_(addr); N_word mask = mask_(addr); N_word msb; boolean carry_out = carry_in; if (size > 0) { msb = mask AND NOT (mask >> 1); while (size-- > 1) { carry_out = ((*addr AND MSB) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; carry_in = carry_out; addr++; } carry_out = ((*addr AND msb) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; *addr &= mask; } return(carry_out); } boolean BitVector_shift_right(wordptr addr, boolean carry_in) { N_word size = size_(addr); N_word mask = mask_(addr); N_word msb; boolean carry_out = carry_in; if (size > 0) { msb = mask AND NOT (mask >> 1); addr += size-1; *addr &= mask; carry_out = ((*addr AND LSB) != 0); *addr >>= 1; if (carry_in) *addr |= msb; carry_in = carry_out; addr--; size--; while (size-- > 0) { carry_out = ((*addr AND LSB) != 0); *addr >>= 1; if (carry_in) *addr |= MSB; carry_in = carry_out; addr--; } } return(carry_out); } void BitVector_Move_Left(wordptr addr, N_int bits) { N_word count; N_word words; if (bits > 0) { count = bits AND MODMASK; words = bits >> LOGBITS; if (bits >= bits_(addr)) BitVector_Empty(addr); else { while (count-- > 0) BitVector_shift_left(addr,0); BitVector_Word_Insert(addr,0,words,TRUE); } } } void BitVector_Move_Right(wordptr addr, N_int bits) { N_word count; N_word words; if (bits > 0) { count = bits AND MODMASK; words = bits >> LOGBITS; if (bits >= bits_(addr)) BitVector_Empty(addr); else { while (count-- > 0) BitVector_shift_right(addr,0); BitVector_Word_Delete(addr,0,words,TRUE); } } } void BitVector_Insert(wordptr addr, N_int offset, N_int count, boolean clear) { N_word bits = bits_(addr); N_word last; if ((count > 0) and (offset < bits)) { last = offset + count; if (last < bits) { BitVector_Interval_Copy(addr,addr,last,offset,(bits-last)); } else last = bits; if (clear) BitVector_Interval_Empty(addr,offset,(last-1)); } } void BitVector_Delete(wordptr addr, N_int offset, N_int count, boolean clear) { N_word bits = bits_(addr); N_word last; if ((count > 0) and (offset < bits)) { last = offset + count; if (last < bits) { BitVector_Interval_Copy(addr,addr,offset,last,(bits-last)); } else count = bits - offset; if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1)); } } boolean BitVector_increment(wordptr addr) /* X++ */ { N_word size = size_(addr); N_word mask = mask_(addr); wordptr last = addr + size - 1; boolean carry = TRUE; if (size > 0) { *last |= NOT mask; while (carry and (size-- > 0)) { carry = (++(*addr++) == 0); } *last &= mask; } return(carry); } boolean BitVector_decrement(wordptr addr) /* X-- */ { N_word size = size_(addr); N_word mask = mask_(addr); wordptr last = addr + size - 1; boolean carry = TRUE; if (size > 0) { *last &= mask; while (carry and (size-- > 0)) { carry = (*addr == 0); --(*addr++); } *last &= mask; } return(carry); } boolean BitVector_compute(wordptr X, wordptr Y, wordptr Z, boolean minus, boolean *carry) { N_word size = size_(X); N_word mask = mask_(X); N_word vv = 0; N_word cc; N_word mm; N_word yy; N_word zz; N_word lo; N_word hi; if (size > 0) { if (minus) cc = (*carry == 0); else cc = (*carry != 0); /* deal with (size-1) least significant full words first: */ while (--size > 0) { yy = *Y++; if (minus) zz = (N_word) NOT ( Z ? *Z++ : 0 ); else zz = (N_word) ( Z ? *Z++ : 0 ); lo = (yy AND LSB) + (zz AND LSB) + cc; hi = (yy >> 1) + (zz >> 1) + (lo >> 1); cc = ((hi AND MSB) != 0); *X++ = (hi << 1) OR (lo AND LSB); } /* deal with most significant word (may be used only partially): */ yy = *Y AND mask; if (minus) zz = (N_word) NOT ( Z ? *Z : 0 ); else zz = (N_word) ( Z ? *Z : 0 ); zz &= mask; if (mask == LSB) /* special case, only one bit used */ { vv = cc; lo = yy + zz + cc; cc = (lo >> 1); vv ^= cc; *X = lo AND LSB; } else { if (NOT mask) /* not all bits are used, but more than one */ { mm = (mask >> 1); vv = (yy AND mm) + (zz AND mm) + cc; mm = mask AND NOT mm; lo = yy + zz + cc; cc = (lo >> 1); vv ^= cc; vv &= mm; cc &= mm; *X = lo AND mask; } else /* other special case, all bits are used */ { mm = NOT MSB; lo = (yy AND mm) + (zz AND mm) + cc; vv = lo AND MSB; hi = ((yy AND MSB) >> 1) + ((zz AND MSB) >> 1) + (vv >> 1); cc = hi AND MSB; vv ^= cc; *X = (hi << 1) OR (lo AND mm); } } if (minus) *carry = (cc == 0); else *carry = (cc != 0); } return(vv != 0); } boolean BitVector_add(wordptr X, wordptr Y, wordptr Z, boolean *carry) { return(BitVector_compute(X,Y,Z,FALSE,carry)); } boolean BitVector_sub(wordptr X, wordptr Y, wordptr Z, boolean *carry) { return(BitVector_compute(X,Y,Z,TRUE,carry)); } boolean BitVector_inc(wordptr X, wordptr Y) { boolean carry = TRUE; return(BitVector_compute(X,Y,NULL,FALSE,&carry)); } boolean BitVector_dec(wordptr X, wordptr Y) { boolean carry = TRUE; return(BitVector_compute(X,Y,NULL,TRUE,&carry)); } void BitVector_Negate(wordptr X, wordptr Y) { N_word size = size_(X); N_word mask = mask_(X); boolean carry = TRUE; if (size > 0) { while (size-- > 0) { *X = NOT *Y++; if (carry) { carry = (++(*X) == 0); } X++; } *(--X) &= mask; } } void BitVector_Absolute(wordptr X, wordptr Y) { N_word size = size_(Y); N_word mask = mask_(Y); if (size > 0) { if (*(Y+size-1) AND (mask AND NOT (mask >> 1))) BitVector_Negate(X,Y); else BitVector_Copy(X,Y); } } Z_int BitVector_Sign(wordptr addr) { N_word size = size_(addr); N_word mask = mask_(addr); wordptr last = addr + size - 1; boolean r = TRUE; if (size > 0) { *last &= mask; while (r and (size-- > 0)) r = ( *addr++ == 0 ); } if (r) return((Z_int) 0); else { if (*last AND (mask AND NOT (mask >> 1))) return((Z_int) -1); else return((Z_int) 1); } } ErrCode BitVector_Mul_Pos(wordptr X, wordptr Y, wordptr Z, boolean strict) { N_word mask; N_word limit; N_word count; Z_long last; wordptr sign; boolean carry; boolean overflow; boolean ok = TRUE; /* Requirements: - X, Y and Z must be distinct - X and Y must have equal sizes (whereas Z may be any size!) - Z should always contain the SMALLER of the two factors Y and Z Constraints: - The contents of Y (and of X, of course) are destroyed (only Z is preserved!) */ if ((X == Y) or (X == Z) or (Y == Z)) return(ErrCode_Same); if (bits_(X) != bits_(Y)) return(ErrCode_Size); BitVector_Empty(X); if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */ if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok); limit = (N_word) last; sign = Y + size_(Y) - 1; mask = mask_(Y); *sign &= mask; mask &= NOT (mask >> 1); for ( count = 0; (ok and (count <= limit)); count++ ) { if ( BIT_VECTOR_TST_BIT(Z,count) ) { carry = false; overflow = BitVector_compute(X,X,Y,false,&carry); if (strict) ok = not (carry or overflow); else ok = not carry; } if (ok and (count < limit)) { carry = BitVector_shift_left(Y,0); if (strict) { overflow = ((*sign AND mask) != 0); ok = not (carry or overflow); } else ok = not carry; } } if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl); } ErrCode BitVector_Multiply(wordptr X, wordptr Y, wordptr Z) { ErrCode error = ErrCode_Ok; N_word bit_x = bits_(X); N_word bit_y = bits_(Y); N_word bit_z = bits_(Z); N_word size; N_word mask; N_word msb; wordptr ptr_y; wordptr ptr_z; boolean sgn_x; boolean sgn_y; boolean sgn_z; boolean zero; wordptr A; wordptr B; /* Requirements: - Y and Z must have equal sizes - X must have at least the same size as Y and Z but may be larger (!) Features: - The contents of Y and Z are preserved - X may be identical with Y or Z (or both!) (in-place multiplication is possible!) */ if ((bit_y != bit_z) or (bit_x < bit_y)) return(ErrCode_Size); if (BitVector_is_empty(Y) or BitVector_is_empty(Z)) { BitVector_Empty(X); } else { A = BitVector_Create(bit_y,FALSE); if (A == NULL) return(ErrCode_Null); B = BitVector_Create(bit_z,FALSE); if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } size = size_(Y); mask = mask_(Y); msb = (mask AND NOT (mask >> 1)); sgn_y = (((*(Y+size-1) &= mask) AND msb) != 0); sgn_z = (((*(Z+size-1) &= mask) AND msb) != 0); sgn_x = sgn_y XOR sgn_z; if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); ptr_y = A + size; ptr_z = B + size; zero = TRUE; while (zero and (size-- > 0)) { zero &= (*(--ptr_y) == 0); zero &= (*(--ptr_z) == 0); } if (*ptr_y > *ptr_z) { if (bit_x > bit_y) { A = BitVector_Resize(A,bit_x); if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); } } error = BitVector_Mul_Pos(X,A,B,TRUE); } else { if (bit_x > bit_z) { B = BitVector_Resize(B,bit_x); if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } } error = BitVector_Mul_Pos(X,B,A,TRUE); } if ((not error) and sgn_x) BitVector_Negate(X,X); BitVector_Destroy(A); BitVector_Destroy(B); } return(error); } ErrCode BitVector_Div_Pos(wordptr Q, wordptr X, wordptr Y, wordptr R) { N_word bits = bits_(Q); N_word mask; wordptr addr; Z_long last; boolean flag; boolean copy = FALSE; /* flags whether valid rest is in R (0) or X (1) */ /* Requirements: - All bit vectors must have equal sizes - Q, X, Y and R must all be distinct bit vectors - Y must be non-zero (of course!) Constraints: - The contents of X (and Q and R, of course) are destroyed (only Y is preserved!) */ if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R))) return(ErrCode_Size); if ((Q == X) or (Q == Y) or (Q == R) or (X == Y) or (X == R) or (Y == R)) return(ErrCode_Same); if (BitVector_is_empty(Y)) return(ErrCode_Zero); BitVector_Empty(R); BitVector_Copy(Q,X); if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok); bits = (N_word) ++last; while (bits-- > 0) { addr = Q + (bits >> LOGBITS); mask = BITMASKTAB[bits AND MODMASK]; flag = ((*addr AND mask) != 0); if (copy) { BitVector_shift_left(X,flag); flag = FALSE; BitVector_compute(R,X,Y,TRUE,&flag); } else { BitVector_shift_left(R,flag); flag = FALSE; BitVector_compute(X,R,Y,TRUE,&flag); } if (flag) *addr &= NOT mask; else { *addr |= mask; copy = not copy; } } if (copy) BitVector_Copy(R,X); return(ErrCode_Ok); } ErrCode BitVector_Divide(wordptr Q, wordptr X, wordptr Y, wordptr R) { ErrCode error = ErrCode_Ok; N_word bits = bits_(Q); N_word size = size_(Q); N_word mask = mask_(Q); N_word msb = (mask AND NOT (mask >> 1)); boolean sgn_q; boolean sgn_x; boolean sgn_y; wordptr A; wordptr B; /* Requirements: - All bit vectors must have equal sizes - Q and R must be two distinct bit vectors - Y must be non-zero (of course!) Features: - The contents of X and Y are preserved - Q may be identical with X or Y (or both) (in-place division is possible!) - R may be identical with X or Y (or both) (but not identical with Q!) */ if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R))) return(ErrCode_Size); if (Q == R) return(ErrCode_Same); if (BitVector_is_empty(Y)) return(ErrCode_Zero); if (BitVector_is_empty(X)) { BitVector_Empty(Q); BitVector_Empty(R); } else { A = BitVector_Create(bits,FALSE); if (A == NULL) return(ErrCode_Null); B = BitVector_Create(bits,FALSE); if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } size--; sgn_x = (((*(X+size) &= mask) AND msb) != 0); sgn_y = (((*(Y+size) &= mask) AND msb) != 0); sgn_q = sgn_x XOR sgn_y; if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X); if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); if (not (error = BitVector_Div_Pos(Q,A,B,R))) { if (sgn_q) BitVector_Negate(Q,Q); if (sgn_x) BitVector_Negate(R,R); } BitVector_Destroy(A); BitVector_Destroy(B); } return(error); } ErrCode BitVector_GCD(wordptr X, wordptr Y, wordptr Z) { ErrCode error = ErrCode_Ok; N_word bits = bits_(X); N_word size = size_(X); N_word mask = mask_(X); N_word msb = (mask AND NOT (mask >> 1)); boolean sgn_a; boolean sgn_b; boolean sgn_r; wordptr Q; wordptr R; wordptr A; wordptr B; wordptr T; /* Requirements: - All bit vectors must have equal sizes Features: - The contents of Y and Z are preserved - X may be identical with Y or Z (or both) (in-place is possible!) - GCD(0,z) == GCD(z,0) == z - negative values are handled correctly */ if ((bits != bits_(Y)) or (bits != bits_(Z))) return(ErrCode_Size); if (BitVector_is_empty(Y)) { if (X != Z) BitVector_Copy(X,Z); return(ErrCode_Ok); } if (BitVector_is_empty(Z)) { if (X != Y) BitVector_Copy(X,Y); return(ErrCode_Ok); } Q = BitVector_Create(bits,false); if (Q == NULL) { return(ErrCode_Null); } R = BitVector_Create(bits,FALSE); if (R == NULL) { BitVector_Destroy(Q); return(ErrCode_Null); } A = BitVector_Create(bits,FALSE); if (A == NULL) { BitVector_Destroy(Q); BitVector_Destroy(R); return(ErrCode_Null); } B = BitVector_Create(bits,FALSE); if (B == NULL) { BitVector_Destroy(Q); BitVector_Destroy(R); BitVector_Destroy(A); return(ErrCode_Null); } size--; sgn_a = (((*(Y+size) &= mask) AND msb) != 0); sgn_b = (((*(Z+size) &= mask) AND msb) != 0); if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); while (not error) { if (not (error = BitVector_Div_Pos(Q,A,B,R))) { if (BitVector_is_empty(R)) break; T = A; sgn_r = sgn_a; A = B; sgn_a = sgn_b; B = R; sgn_b = sgn_r; R = T; } } if (not error) { if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B); } BitVector_Destroy(Q); BitVector_Destroy(R); BitVector_Destroy(A); BitVector_Destroy(B); return(error); } ErrCode BitVector_GCD2(wordptr U, wordptr V, wordptr W, wordptr X, wordptr Y) { ErrCode error = ErrCode_Ok; N_word bits = bits_(U); N_word size = size_(U); N_word mask = mask_(U); N_word msb = (mask AND NOT (mask >> 1)); boolean minus; boolean carry; boolean sgn_q; boolean sgn_r; boolean sgn_a; boolean sgn_b; boolean sgn_x; boolean sgn_y; listptr L; wordptr Q; wordptr R; wordptr A; wordptr B; wordptr T; wordptr X1; wordptr X2; wordptr X3; wordptr Y1; wordptr Y2; wordptr Y3; wordptr Z; /* Requirements: - All bit vectors must have equal sizes - U, V, and W must all be distinct bit vectors Features: - The contents of X and Y are preserved - U, V and W may be identical with X or Y (or both, provided that U, V and W are mutually distinct) (i.e., in-place is possible!) - GCD(0,z) == GCD(z,0) == z - negative values are handled correctly */ if ((bits != bits_(V)) or (bits != bits_(W)) or (bits != bits_(X)) or (bits != bits_(Y))) { return(ErrCode_Size); } if ((U == V) or (U == W) or (V == W)) { return(ErrCode_Same); } if (BitVector_is_empty(X)) { if (U != Y) BitVector_Copy(U,Y); BitVector_Empty(V); BitVector_Empty(W); *W = 1; return(ErrCode_Ok); } if (BitVector_is_empty(Y)) { if (U != X) BitVector_Copy(U,X); BitVector_Empty(V); BitVector_Empty(W); *V = 1; return(ErrCode_Ok); } if ((L = BitVector_Create_List(bits,false,11)) == NULL) { return(ErrCode_Null); } Q = L[0]; R = L[1]; A = L[2]; B = L[3]; X1 = L[4]; X2 = L[5]; X3 = L[6]; Y1 = L[7]; Y2 = L[8]; Y3 = L[9]; Z = L[10]; size--; sgn_a = (((*(X+size) &= mask) AND msb) != 0); sgn_b = (((*(Y+size) &= mask) AND msb) != 0); if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X); if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); BitVector_Empty(X1); BitVector_Empty(X2); *X1 = 1; BitVector_Empty(Y1); BitVector_Empty(Y2); *Y2 = 1; sgn_x = false; sgn_y = false; while (not error) { if ((error = BitVector_Div_Pos(Q,A,B,R))) { break; } if (BitVector_is_empty(R)) { break; } sgn_q = sgn_a XOR sgn_b; if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2); if ((error = BitVector_Mul_Pos(X3,Z,Q,true))) { break; } minus = not (sgn_x XOR sgn_q); carry = 0; if (BitVector_compute(X3,X1,X3,minus,&carry)) { error = ErrCode_Ovfl; break; } sgn_x = (((*(X3+size) &= mask) AND msb) != 0); if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2); if ((error = BitVector_Mul_Pos(Y3,Z,Q,true))) { break; } minus = not (sgn_y XOR sgn_q); carry = 0; if (BitVector_compute(Y3,Y1,Y3,minus,&carry)) { error = ErrCode_Ovfl; break; } sgn_y = (((*(Y3+size) &= mask) AND msb) != 0); T = A; sgn_r = sgn_a; A = B; sgn_a = sgn_b; B = R; sgn_b = sgn_r; R = T; T = X1; X1 = X2; X2 = X3; X3 = T; T = Y1; Y1 = Y2; Y2 = Y3; Y3 = T; } if (not error) { if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B); BitVector_Copy(V,X2); BitVector_Copy(W,Y2); } BitVector_Destroy_List(L,11); return(error); } ErrCode BitVector_Power(wordptr X, wordptr Y, wordptr Z) { ErrCode error = ErrCode_Ok; N_word bits = bits_(X); boolean first = TRUE; Z_long last; N_word limit; N_word count; wordptr T; /* Requirements: - X must have at least the same size as Y but may be larger (!) - X may not be identical with Z - Z must be positive Features: - The contents of Y and Z are preserved */ if (X == Z) return(ErrCode_Same); if (bits < bits_(Y)) return(ErrCode_Size); if (BitVector_msb_(Z)) return(ErrCode_Expo); if ((last = Set_Max(Z)) < 0L) { if (bits < 2) return(ErrCode_Ovfl); BitVector_Empty(X); *X |= LSB; return(ErrCode_Ok); /* anything ^ 0 == 1 */ } if (BitVector_is_empty(Y)) { if (X != Y) BitVector_Empty(X); return(ErrCode_Ok); /* 0 ^ anything not zero == 0 */ } T = BitVector_Create(bits,FALSE); if (T == NULL) return(ErrCode_Null); limit = (N_word) last; for ( count = 0; ((!error) and (count <= limit)); count++ ) { if ( BIT_VECTOR_TST_BIT(Z,count) ) { if (first) { first = FALSE; if (count) { BitVector_Copy(X,T); } else { if (X != Y) BitVector_Copy(X,Y); } } else error = BitVector_Multiply(X,T,X); /* order important because T > X */ } if ((!error) and (count < limit)) { if (count) error = BitVector_Multiply(T,T,T); else error = BitVector_Multiply(T,Y,Y); } } BitVector_Destroy(T); return(error); } void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length) { N_word size = size_(addr); N_word mask = mask_(addr); N_word value; N_word count; /* provide translation for independence of endian-ness: */ if (size > 0) { while (size-- > 0) { value = 0; for ( count = 0; (length > 0) and (count < BITS); count += 8 ) { value |= (((N_word) *buffer++) << count); length--; } *addr++ = value; } *(--addr) &= mask; } } charptr BitVector_Block_Read(wordptr addr, N_intptr length) { N_word size = size_(addr); N_word value; N_word count; charptr buffer; charptr target; /* provide translation for independence of endian-ness: */ *length = size << FACTOR; buffer = (charptr) yasm_xmalloc((size_t) ((*length)+1)); if (buffer == NULL) return(NULL); target = buffer; if (size > 0) { *(addr+size-1) &= mask_(addr); while (size-- > 0) { value = *addr++; count = BITS >> 3; while (count-- > 0) { *target++ = (N_char) (value AND 0x00FF); if (count > 0) value >>= 8; } } } *target = (N_char) '\0'; return(buffer); } void BitVector_Word_Store(wordptr addr, N_int offset, N_int value) { N_word size = size_(addr); if (size > 0) { if (offset < size) *(addr+offset) = value; *(addr+size-1) &= mask_(addr); } } N_int BitVector_Word_Read(wordptr addr, N_int offset) { N_word size = size_(addr); if (size > 0) { *(addr+size-1) &= mask_(addr); if (offset < size) return( *(addr+offset) ); } return( (N_int) 0 ); } void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count, boolean clear) { N_word size = size_(addr); N_word mask = mask_(addr); wordptr last = addr+size-1; if (size > 0) { *last &= mask; if (offset > size) offset = size; BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear); *last &= mask; } } void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count, boolean clear) { N_word size = size_(addr); N_word mask = mask_(addr); wordptr last = addr+size-1; if (size > 0) { *last &= mask; if (offset > size) offset = size; BIT_VECTOR_del_words(addr+offset,size-offset,count,clear); *last &= mask; } } void BitVector_Chunk_Store(wordptr addr, N_int chunksize, N_int offset, N_long value) { N_word bits = bits_(addr); N_word mask; N_word temp; if ((chunksize > 0) and (offset < bits)) { if (chunksize > LONGBITS) chunksize = LONGBITS; if ((offset + chunksize) > bits) chunksize = bits - offset; addr += offset >> LOGBITS; offset &= MODMASK; while (chunksize > 0) { mask = (N_word) (~0L << offset); bits = offset + chunksize; if (bits < BITS) { mask &= (N_word) ~(~0L << bits); bits = chunksize; } else bits = BITS - offset; temp = (N_word) (value << offset); temp &= mask; *addr &= NOT mask; *addr++ |= temp; value >>= bits; chunksize -= bits; offset = 0; } } } N_long BitVector_Chunk_Read(wordptr addr, N_int chunksize, N_int offset) { N_word bits = bits_(addr); N_word chunkbits = 0; N_long value = 0L; N_long temp; N_word mask; if ((chunksize > 0) and (offset < bits)) { if (chunksize > LONGBITS) chunksize = LONGBITS; if ((offset + chunksize) > bits) chunksize = bits - offset; addr += offset >> LOGBITS; offset &= MODMASK; while (chunksize > 0) { bits = offset + chunksize; if (bits < BITS) { mask = (N_word) ~(~0L << bits); bits = chunksize; } else { mask = (N_word) ~0L; bits = BITS - offset; } temp = (N_long) ((*addr++ AND mask) >> offset); value |= temp << chunkbits; chunkbits += bits; chunksize -= bits; offset = 0; } } return(value); } /*******************/ /* set operations: */ /*******************/ void Set_Union(wordptr X, wordptr Y, wordptr Z) /* X = Y + Z */ { N_word bits = bits_(X); N_word size = size_(X); N_word mask = mask_(X); if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) { while (size-- > 0) *X++ = *Y++ OR *Z++; *(--X) &= mask; } } void Set_Intersection(wordptr X, wordptr Y, wordptr Z) /* X = Y * Z */ { N_word bits = bits_(X); N_word size = size_(X); N_word mask = mask_(X); if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) { while (size-- > 0) *X++ = *Y++ AND *Z++; *(--X) &= mask; } } void Set_Difference(wordptr X, wordptr Y, wordptr Z) /* X = Y \ Z */ { N_word bits = bits_(X); N_word size = size_(X); N_word mask = mask_(X); if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) { while (size-- > 0) *X++ = *Y++ AND NOT *Z++; *(--X) &= mask; } } void Set_ExclusiveOr(wordptr X, wordptr Y, wordptr Z) /* X=(Y+Z)\(Y*Z) */ { N_word bits = bits_(X); N_word size = size_(X); N_word mask = mask_(X); if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z))) { while (size-- > 0) *X++ = *Y++ XOR *Z++; *(--X) &= mask; } } void Set_Complement(wordptr X, wordptr Y) /* X = ~Y */ { N_word size = size_(X); N_word mask = mask_(X); if ((size > 0) and (bits_(X) == bits_(Y))) { while (size-- > 0) *X++ = NOT *Y++; *(--X) &= mask; } } /******************/ /* set functions: */ /******************/ boolean Set_subset(wordptr X, wordptr Y) /* X subset Y ? */ { N_word size = size_(X); boolean r = FALSE; if ((size > 0) and (bits_(X) == bits_(Y))) { r = TRUE; while (r and (size-- > 0)) r = ((*X++ AND NOT *Y++) == 0); } return(r); } N_int Set_Norm(wordptr addr) /* = | X | */ { byteptr byte; N_word bytes; N_int n; byte = (byteptr) addr; bytes = size_(addr) << FACTOR; n = 0; while (bytes-- > 0) { n += BitVector_BYTENORM[*byte++]; } return(n); } N_int Set_Norm2(wordptr addr) /* = | X | */ { N_word size = size_(addr); N_word w0,w1; N_int n,k; n = 0; while (size-- > 0) { k = 0; w1 = NOT (w0 = *addr++); while (w0 and w1) { w0 &= w0 - 1; w1 &= w1 - 1; k++; } if (w0 == 0) n += k; else n += BITS - k; } return(n); } N_int Set_Norm3(wordptr addr) /* = | X | */ { N_word size = size_(addr); N_int count = 0; N_word c; while (size-- > 0) { c = *addr++; while (c) { c &= c - 1; count++; } } return(count); } Z_long Set_Min(wordptr addr) /* = min(X) */ { boolean empty = TRUE; N_word size = size_(addr); N_word i = 0; N_word c = 0; /* silence compiler warning */ while (empty and (size-- > 0)) { if ((c = *addr++)) empty = false; else i++; } if (empty) return((Z_long) LONG_MAX); /* plus infinity */ i <<= LOGBITS; while (not (c AND LSB)) { c >>= 1; i++; } return((Z_long) i); } Z_long Set_Max(wordptr addr) /* = max(X) */ { boolean empty = TRUE; N_word size = size_(addr); N_word i = size; N_word c = 0; /* silence compiler warning */ addr += size-1; while (empty and (size-- > 0)) { if ((c = *addr--)) empty = false; else i--; } if (empty) return((Z_long) LONG_MIN); /* minus infinity */ i <<= LOGBITS; while (not (c AND MSB)) { c <<= 1; i--; } return((Z_long) --i); } /**********************************/ /* matrix-of-booleans operations: */ /**********************************/ void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX, wordptr Y, N_int rowsY, N_int colsY, wordptr Z, N_int rowsZ, N_int colsZ) { N_word i; N_word j; N_word k; N_word indxX; N_word indxY; N_word indxZ; N_word termX; N_word termY; N_word sum; if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and (bits_(X) == rowsX*colsX) and (bits_(Y) == rowsY*colsY) and (bits_(Z) == rowsZ*colsZ)) { for ( i = 0; i < rowsY; i++ ) { termX = i * colsX; termY = i * colsY; for ( j = 0; j < colsZ; j++ ) { indxX = termX + j; sum = 0; for ( k = 0; k < colsY; k++ ) { indxY = termY + k; indxZ = k * colsZ + j; if ( BIT_VECTOR_TST_BIT(Y,indxY) && BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1; } if (sum) BIT_VECTOR_SET_BIT(X,indxX) else BIT_VECTOR_CLR_BIT(X,indxX) } } } } void Matrix_Product(wordptr X, N_int rowsX, N_int colsX, wordptr Y, N_int rowsY, N_int colsY, wordptr Z, N_int rowsZ, N_int colsZ) { N_word i; N_word j; N_word k; N_word indxX; N_word indxY; N_word indxZ; N_word termX; N_word termY; N_word sum; if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and (bits_(X) == rowsX*colsX) and (bits_(Y) == rowsY*colsY) and (bits_(Z) == rowsZ*colsZ)) { for ( i = 0; i < rowsY; i++ ) { termX = i * colsX; termY = i * colsY; for ( j = 0; j < colsZ; j++ ) { indxX = termX + j; sum = 0; for ( k = 0; k < colsY; k++ ) { indxY = termY + k; indxZ = k * colsZ + j; if ( BIT_VECTOR_TST_BIT(Y,indxY) && BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1; } if (sum) BIT_VECTOR_SET_BIT(X,indxX) else BIT_VECTOR_CLR_BIT(X,indxX) } } } } void Matrix_Closure(wordptr addr, N_int rows, N_int cols) { N_word i; N_word j; N_word k; N_word ii; N_word ij; N_word ik; N_word kj; N_word termi; N_word termk; if ((rows == cols) and (bits_(addr) == rows*cols)) { for ( i = 0; i < rows; i++ ) { ii = i * cols + i; BIT_VECTOR_SET_BIT(addr,ii) } for ( k = 0; k < rows; k++ ) { termk = k * cols; for ( i = 0; i < rows; i++ ) { termi = i * cols; ik = termi + k; for ( j = 0; j < rows; j++ ) { ij = termi + j; kj = termk + j; if ( BIT_VECTOR_TST_BIT(addr,ik) && BIT_VECTOR_TST_BIT(addr,kj) ) BIT_VECTOR_SET_BIT(addr,ij) } } } } } void Matrix_Transpose(wordptr X, N_int rowsX, N_int colsX, wordptr Y, N_int rowsY, N_int colsY) { N_word i; N_word j; N_word ii; N_word ij; N_word ji; N_word addii; N_word addij; N_word addji; N_word bitii; N_word bitij; N_word bitji; N_word termi; N_word termj; boolean swap; /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */ if ((rowsX == colsY) and (colsX == rowsY) and (bits_(X) == rowsX*colsX) and (bits_(Y) == rowsY*colsY)) { if (rowsY == colsY) /* in-place is possible! */ { for ( i = 0; i < rowsY; i++ ) { termi = i * colsY; for ( j = 0; j < i; j++ ) { termj = j * colsX; ij = termi + j; ji = termj + i; addij = ij >> LOGBITS; addji = ji >> LOGBITS; bitij = BITMASKTAB[ij AND MODMASK]; bitji = BITMASKTAB[ji AND MODMASK]; swap = ((*(Y+addij) AND bitij) != 0); if ((*(Y+addji) AND bitji) != 0) *(X+addij) |= bitij; else *(X+addij) &= NOT bitij; if (swap) *(X+addji) |= bitji; else *(X+addji) &= NOT bitji; } ii = termi + i; addii = ii >> LOGBITS; bitii = BITMASKTAB[ii AND MODMASK]; if ((*(Y+addii) AND bitii) != 0) *(X+addii) |= bitii; else *(X+addii) &= NOT bitii; } } else /* rowsX != colsX, in-place is NOT possible! */ { for ( i = 0; i < rowsY; i++ ) { termi = i * colsY; for ( j = 0; j < colsY; j++ ) { termj = j * colsX; ij = termi + j; ji = termj + i; addij = ij >> LOGBITS; addji = ji >> LOGBITS; bitij = BITMASKTAB[ij AND MODMASK]; bitji = BITMASKTAB[ji AND MODMASK]; if ((*(Y+addij) AND bitij) != 0) *(X+addji) |= bitji; else *(X+addji) &= NOT bitji; } } } } } /*****************************************************************************/ /* VERSION: 6.4 */ /*****************************************************************************/ /* VERSION HISTORY: */ /*****************************************************************************/ /* */ /* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */ /* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */ /* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */ /* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */ /* Version 6.0 08.10.00 Corrected overflow handling. */ /* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */ /* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */ /* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */ /* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */ /* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */ /* Version 5.3 12.05.98 Improved Norm. Completed history. */ /* Version 5.2 31.03.98 Improved Norm. */ /* Version 5.1 09.03.98 No changes. */ /* Version 5.0 01.03.98 Major additions and rewrite. */ /* Version 4.2 16.07.97 Added is_empty, is_full. */ /* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */ /* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */ /* Version 3.2 04.02.97 Added interval methods. */ /* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */ /* Version 3.0 12.01.97 Added flip. */ /* Version 2.0 14.12.96 Efficiency and consistency improvements. */ /* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */ /* Version 1.0 14.12.95 First version under UNIX (with Perl module). */ /* Version 0.9 01.11.93 First version of C library under MS-DOS. */ /* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */ /* */ /*****************************************************************************/ /* AUTHOR: */ /*****************************************************************************/ /* */ /* Steffen Beyer */ /* mailto:sb@engelschall.com */ /* http://www.engelschall.com/u/sb/download/ */ /* */ /*****************************************************************************/ /* COPYRIGHT: */ /*****************************************************************************/ /* */ /* Copyright (c) 1995 - 2004 by Steffen Beyer. */ /* All rights reserved. */ /* */ /*****************************************************************************/ /* LICENSE: */ /*****************************************************************************/ /* This package is free software; you can use, modify and redistribute */ /* it under the same terms as Perl itself, i.e., under the terms of */ /* the "Artistic License" or the "GNU General Public License". */ /* */ /* The C library at the core of this Perl module can additionally */ /* be used, modified and redistributed under the terms of the */ /* "GNU Library General Public License". */ /* */ /*****************************************************************************/ /* ARTISTIC LICENSE: */ /*****************************************************************************/ /* The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End */ /*****************************************************************************/ /* GNU GENERAL PUBLIC LICENSE: */ /*****************************************************************************/ /* This program is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version 2 */ /* of the License, or (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the */ /* Free Software Foundation, Inc., */ /* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* */ /*****************************************************************************/ /* GNU LIBRARY GENERAL PUBLIC LICENSE: */ /*****************************************************************************/ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public */ /* License as published by the Free Software Foundation; either */ /* version 2 of the License, or (at your option) any later version. */ /* */ /* This library is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* Library General Public License for more details. */ /* */ /* You should have received a copy of the GNU Library General Public */ /* License along with this library; if not, write to the */ /* Free Software Foundation, Inc., */ /* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */ /* */ /*****************************************************************************/