Você está na página 1de 8

/* BITOPS.C - Various bit-manipulation procedures. * * Audit Trail * * 09/11/87 - v001 - GSK - Original */ #include "ctype.

h" #define #define #define #define #define FULLBYT 0xff TBUFSIZ 100 SUCCESS 0 FAILURE -1 NULL (char *)0

typedef unsigned BOOL; /* *************************** GENERAL NOTES ***************************** * * Most of these routines deal with "bit fields" of arbitrary * length. In general, you pass them a (char) pointer to a block of memory, * which will be interpreted and manipulated as a stream of bits, regardless * of byte or word boundaries after the original pointer. Several of these * routines take a bit offset argument, which is an ABSOLUTE number of bits * (zero-relative) from the base pointer; in other words, a bit offset of * 75 points to the 76th bit in the block, starting from the base pointer. * ****************************************************************************/

/* GETBIT - Get the value of the bit (0, 1) at passed ptr, offset by bitoffs * bits. The offset may be any positive number; if >8, the byte * pointer will be incremented accordingly. */ short getbit(ptr, bitoffs) char *ptr; short bitoffs; { if (ptr == NULL || bitoffs < 0) return (FAILURE); ptr += (bitoffs / 8); bitoffs %= 8; /* Knock up ptr to byte requested */ /* Get bit relative to its own byte */ /* Base pointer */ /* Offset from ptr in number of bits */

return (short)((*ptr >> (7 - bitoffs)) & 1); }

/* SETBIT - Set a specified bit number in a char string to 1 or 0. The bit * number may be any positive value; if > 8, the byte pointer will * be incremented accordingly. */ short setbit(ptr, bitnum, val)

char *ptr; short bitnum; short val; {

/* Base of string */ /* Bit number, 0 relative */ /* Value to set, 1 or 0 */

short byteoffs; char mask;

/* Byte offset in string */ /* Masking value */

if (ptr == NULL || bitnum < 0 || (val != 0 && val != 1)) return (FAILURE); ptr += (byteoffs = bitnum / 8); if (byteoffs) bitnum %= (byteoffs * 8); /* Calc offset, reset ptr */

/* Find bit within byte */

/* Mask = bit string of zeroes with one in bitnum position */ mask = 1 << (7 - bitnum); if (val) *ptr |= mask; else *ptr &= ~mask; return (SUCCESS); } /* If turn-on bit, OR with mask */ /* Else, AND with inverse (ones-complement) of mask */

/* COUNTBIT - Count the bits of specified value (0 or 1) in a bit field. The * field may be any number of bytes in length. If val==0, then * "off" bits will be counted; otherwise, "on" bits. */ short countbit(basep, nbytes, val) char *basep; short nbytes; short val; { short count; short bit; char *ptr; /* Number of bits counted */ /* Bit loop counter */ /* Loop pointer */ /* Starting byte to begin count */ /* Number of bytes to count thru */ /* Bit value to count, 0 or 1 */

if (basep == NULL || nbytes <= 0 || (val != 0 && val != 1)) return (FAILURE); count = 0; for (ptr = basep; ptr < basep + nbytes; ptr++) { for (bit = 0; bit < 8; bit++) count += (getbit(ptr, bit) == val); } return (count); }

/* BITPATRN * * * * * * * */

Generate an array of chars or ints corresponding to the bit pattern of the passed char. If patyp == C, an array of character 0s and 1s will be generated; if I, an array numeric 0/1s. NOTE that you pass a single CHAR, not a char *. Thus if you need a pattern array more than 8 elements long, call bitpatrn() in a loop and concatenate the results.

short bitpatrn(chr, patp, patyp) char chr; char *patp; char patyp; { short ptrinc; short bit; short bitval; /* Pointer increment per bit */ /* Bit counter */ /* Bit value, 1 or 0 */ /* Char to generate pattern from */ /* Ptr to array of chars or ints, depending on patyp */ /* Pattern type: Char or Int (NOT case sensitive) */

patyp = toupper(patyp); if (patp == NULL || (patyp != C && patyp != I)) return (FAILURE); ptrinc = 1 + (patyp == I); for (bit = 0; bit < 8; bit++, patp += ptrinc) { bitval = getbit(&chr, bit); if (patyp == I) /* Int array: Set low bytes of each pair */ { *patp = bitval; *(patp + 1) = 0; } else *patp = 0 + bitval; } return (SUCCESS); }

/* BYTE2BIT * * * * * * * * * * * *

Translate the byte passed to a bit pattern, placed at char *ptr, offset by bitoffs bits from left. Do not write onto next byte from ptr if lastbyt set. This allows a bit pattern to be copied to another place in memory regardless of byte boundaries. For example, if bitoffs == 3, then the left 5 bits of the passed byte will be copied to the right 5 bits of the destination ptr, and the right 3 bits of the byte onto the left 3 bits of the following location (unless lastbyt == YES), in which case only the FIRST dest char will be written on). Issuing a call with a ZERO bit offset, like: byte2bit(A, dest, 0, anything);

* */

is equivalent to: *dest = A;

short byte2bit(byte, ptr, bitoffs, lastbyt) char byte; char *ptr; short bitoffs; BOOL lastbyt; { short bit; /* Bit counter */ /* Character to translate */ /* DESTINATION Ptr: Points to starting byte to write to */ /* Offset of starting bit from DESTINATION ptr, 0-7 */ /* Flag: Do not write bits to next char if set */

if (ptr == NULL || bitoffs < 0 || bitoffs > 7) return (FAILURE); /* Write left side of passed byte to right side of 1st destination char, leaving left side of dest char unchanged */ for (bit = bitoffs; bit <= 7; bit++) setbit(ptr, bit, getbit(&byte, bit - bitoffs)); /* Write right side of byte to left side of next destination char, leaving right side unchanged */ if (bitoffs && !lastbyt) for (bit = 0; bit < bitoffs; bit++) setbit(ptr + 1, bit, getbit(&byte, bit + 8 - bitoffs)); return (SUCCESS); }

/* BIT2BYTE.C - Take next 8 bits from starting char *, offset by specified * number of bits (bitoffs), translate to a byte and return * value as a char. Starting point need not conform to a byte * boundary. For example, if bitoffs = 3, then translation will * begin with the 4th bit (offsets are 0-relative) of the passed * ptr; if lastbyt == YES, then only the remaining 5 bits will * be translated (offsets 3 thru 7); otherwise, a full 8 bits * will be translated, the remaining 3 coming from the left 3 * bits of the byte following ptr. Issuing a call with a ZERO * bit offset like: * * mychar = bit2byte(there, 0, anything); * * is equivalent to: mychar = *there; */ char bit2byte(ptr, bitoffs, lastbyt) char *ptr; short bitoffs; BOOL lastbyt; { char byte; /* Ptr to starting byte to take from */ /* Offset of starting bit from ptr, 0-7 */ /* Flag: Do not take bits from next char if set */

if (ptr == NULL || bitoffs < 0 || bitoffs > 7) return (0); byte = *ptr << bitoffs; if (bitoffs && !lastbyt) /* Set left side of byte */ /* Set right side from next byte */

byte |= (*(++ptr) >> (8 - bitoffs)); return (byte); }

/* INSBITS - Insert specified number of bits to bit field beginning at basep, * starting insertion bitoffs bits from the base. Inserted bits * will be all of the same value (0 or 1). Bits above the * insertion point will be pushed up in memory, up the limit of * total field size fldsize (arbitrary size limit defined by * TBUFSIZ). * * NOTE: If you need a routine to insert a specific bit pattern * (not just all 0s or 1s), use this as a template. You only * need to change the "fill middle bytes" section. */ short insbits(basep, bitoffs, nbits, val, fldsize) char *basep; short bitoffs; short nbits; short val; short fldsize; { char buffer[TBUFSIZ]; char *firstbyt, *lastbyt; short firstoffs, lastoffs; short n; short lastbit; char *ptr; /* Temporary copy buffer */ /* Bytes where insert begins/ends */ /* Bit offsets in first, last bytes */ /* Field index counter */ /* Offset of last bit in field */ /* Temporary ptr */ /* Ptr to base of bit field */ /* Number of bits offset from left to begin insert */ /* Number of bits to insert */ /* Value to insert, 1 or 0 */ /* Total size of bit field in bytes */

if (basep == NULL || nbits <= 0 || fldsize <= 0 || fldsize > TBUFSIZ) return (FAILURE); firstbyt = basep + bitoffs / 8; lastbit = bitoffs + nbits - 1; lastbyt = basep + lastbit / 8; firstoffs = bitoffs % 8; lastoffs = lastbit % 8; if (firstbyt >= basep + fldsize) return (FAILURE); setmem(buffer, sizeof(buffer), 0); /* Init copy buffer */

/* Copy from firstbyt thru end of field to buffer */ for (ptr = firstbyt, n = 0; ptr < basep + fldsize; ptr++, n++) buffer[n] = bit2byte(ptr, firstoffs, ptr == basep + fldsize - 1);

/* Set the starting byte, leaving left part as is */ if (val) *firstbyt |= FULLBYT >> firstoffs; else *firstbyt &= FULLBYT << (8 - firstoffs); /* Fill middle bytes; do not overwrite end of field */ for (ptr = firstbyt + 1; ptr < lastbyt; ptr++) { if (ptr >= basep + fldsize) break; *ptr = (val) ? FULLBYT : 0; } /* Set ending byte, leaving right part as is */ if (lastbyt < basep + fldsize && lastbyt != firstbyt) { if (val) *lastbyt |= FULLBYT << (7 - lastoffs); else *lastbyt &= FULLBYT >> (lastoffs + 1); } /* Write buffer from last byte to end of field */ for (ptr = lastbyt, n = 0; ptr < basep + fldsize; ptr++, n++) byte2bit(buffer[n], ptr, lastoffs + 1, ptr == basep + fldsize - 1); return (SUCCESS); }

/* DELBITS.C - Delete specified number of bits from bit field beginning at * basep offset by bitoffs bits. The bit field may be any number * of bytes in length, and the deleted section may be any number * of bits in length and need not conform to byte boundaries. The * bits above the deleted section are moved down to fill the * gap, and the top of the field filled with the specified value. * * NOTE: Bit field size fldsize is arbitrarily limited to TBUFSIZ as * defined below. */ short delbits(basep, bitoffs, nbits, val, fldsize) char *basep; short bitoffs; short nbits; short val; short fldsize; { char buffer[TBUFSIZ]; char *firstbyt, *lastbyt; short firstoffs, lastoffs; /* Temporary copy buffer */ /* Bytes where delete begins/ends */ /* Bit offsets in first, last bytes */ /* Ptr to base of bit field */ /* Number of bits offset from left to begin delete */ /* Number of bits to delete */ /* Value to fill vacated right side of field, 1 or 0 */ /* Total size of bit field in BYTES */

short n; short lastbit; char *ptr;

/* Field index counter */ /* Offset of last bit in field */ /* Temporary ptr */

if (basep == NULL || nbits <= 0 || fldsize <= 0 || fldsize > TBUFSIZ) return (FAILURE); firstbyt = basep + bitoffs / 8; lastbit = bitoffs + nbits - 1; lastbyt = basep + lastbit / 8; firstoffs = bitoffs % 8; lastoffs = lastbit % 8; if (firstbyt >= basep + fldsize) return (FAILURE); if (val) setmem(buffer, sizeof(buffer), FULLBYT); else setmem(buffer, sizeof(buffer), 0);

/* Init copy buffer */

/* Copy to buffer: From bit after end of deleted section to end of field */ if (++lastoffs > 7) { lastbyt++; lastoffs = 0; } for (ptr = lastbyt, n = 0; ptr < basep + fldsize; ptr++, n++) buffer[n] = bit2byte(ptr, lastoffs, ptr == basep + fldsize - 1); /* Write buffer to deleted part thru end of field; end is filled with val */ for (ptr = firstbyt, n = 0; ptr < basep + fldsize; ptr++, n++) byte2bit(buffer[n], ptr, firstoffs, ptr == basep + fldsize - 1); return (SUCCESS); }

/* BITZVALU - Evaluate the next nbits bits from the starting char * and bit * offset and return the value. Uses a simple counting algorithm, * starting with the rightmost bit in the designated field and * moving left, adding a successive power of 2 for each "on" bit. * * EXAMPLES: Given a pointer to the array of hex values: 1E A4 7C * * bitzvalu(ptr, 8, 8) returns 164 (00 * bitzvalu(ptr, 3, 4) returns 15 (00 * bitzvalu(ptr, 10, 10) returns 583 (0247) * * NOTE: Returns an unsigned value. The number of bits evaluated may not * be more than 16. If bad parameters are passed, returns 0. */ unsigned bitzvalu(ptr, bitoffs, nbits) char *ptr; /* Ptr to starting byte to take from */

short bitoffs; /* Offset of starting bit from ptr */ short nbits; /* Number of bits to evaluate */ { unsigned num = 0; /* Initialize all bits to 0 */ int bit; unsigned mult = 1; if (ptr == NULL || nbits < 1 || nbits > 16) return (0); for (bit = nbits - 1; bit >= 0; bit--, mult *= 2) num += (getbit(ptr, bitoffs + bit) * mult); return (num); }

/* CONTRIBUTED BY: Gordon Kramer, Liberty Tree Software, Belchertown, MA */

Você também pode gostar