#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h> /* for CHAR_BIT */

unsigned long
getbit8(unsigned char *b,	/**< octet sequence */
	unsigned pos,		/**< 0 to 7 */
	unsigned width)		/**< 0 to 8 */
{
  unsigned mask;
  if (width == 0) {
    return 0;
  } else if (width == 1) {
    switch (pos) {
    case 0: return 1u & (b[0] >> 7);
    case 1: return 1u & (b[0] >> 6);
    case 2: return 1u & (b[0] >> 5);
    case 3: return 1u & (b[0] >> 4);
    case 4: return 1u & (b[0] >> 3);
    case 5: return 1u & (b[0] >> 2);
    case 6: return 1u & (b[0] >> 1);
    case 7: return 1u & (b[0] >> 0);
    }
  } else if (width == 2) {
    switch (pos) {
    case 0: return 3u & (b[0] >> 6);
    case 1: return 3u & (b[0] >> 5);
    case 2: return 3u & (b[0] >> 4);
    case 3: return 3u & (b[0] >> 3);
    case 4: return 3u & (b[0] >> 2);
    case 5: return 3u & (b[0] >> 1);
    case 6: return 3u & (b[0] >> 0);
    case 7: return 3u & (b[0] << 1 | b[1] >> 7);
    }
  } else if (width == 3) {
    switch (pos) {
    case 0: return 7u & (b[0] >> 5);
    case 1: return 7u & (b[0] >> 4);
    case 2: return 7u & (b[0] >> 3);
    case 3: return 7u & (b[0] >> 2);
    case 4: return 7u & (b[0] >> 1);
    case 5: return 7u & (b[0] >> 0);
    case 6: return 7u & (b[0] << 1 | b[1] >> 7);
    case 7: return 7u & (b[0] << 2 | b[1] >> 6);
    }
  } else if (width == 4) {
    switch (pos) {
    case 0: return 0xFu & (b[0] >> 4);
    case 1: return 0xFu & (b[0] >> 3);
    case 2: return 0xFu & (b[0] >> 2);
    case 3: return 0xFu & (b[0] >> 1);
    case 4: return 0xFu & (b[0] >> 0);
    case 5: return 0xFu & (b[0] << 1 | b[1] >> 7);
    case 6: return 0xFu & (b[0] << 2 | b[1] >> 6);
    case 7: return 0xFu & (b[0] << 3 | b[1] >> 5);
    }
  } else if (width == 5) {
    switch (pos) {
    case 0: return 0x1Fu & (b[0] >> 3);
    case 1: return 0x1Fu & (b[0] >> 2);
    case 2: return 0x1Fu & (b[0] >> 1);
    case 3: return 0x1Fu & (b[0] >> 0);
    case 4: return 0x1Fu & (b[0] << 1 | b[1] >> 7);
    case 5: return 0x1Fu & (b[0] << 2 | b[1] >> 6);
    case 6: return 0x1Fu & (b[0] << 3 | b[1] >> 5);
    case 7: return 0x1Fu & (b[0] << 4 | b[1] >> 4);
    }
  } else if (width == 6) {
    switch (pos) {
    case 0: return 0x1Fu & (b[0] >> 3);
    case 1: return 0x1Fu & (b[0] >> 2);
    case 2: return 0x1Fu & (b[0] >> 1);
    case 3: return 0x1Fu & (b[0] >> 0);
    case 4: return 0x1Fu & (b[0] << 1 | b[1] >> 7);
    case 5: return 0x1Fu & (b[0] << 2 | b[1] >> 6);
    case 6: return 0x1Fu & (b[0] << 3 | b[1] >> 5);
    case 7: return 0x1Fu & (b[0] << 4 | b[1] >> 4);
    }
  } else if (width == 5) {
    switch (pos) {
    case 0: return 0x1Fu & (b[0] >> 3);
    case 1: return 0x1Fu & (b[0] >> 2);
    case 2: return 0x1Fu & (b[0] >> 1);
    case 3: return 0x1Fu & (b[0] >> 0);
    case 4: return 0x1Fu & (b[0] << 1 | b[1] >> 7);
    case 5: return 0x1Fu & (b[0] << 2 | b[1] >> 6);
    case 6: return 0x1Fu & (b[0] << 3 | b[1] >> 5);
    case 7: return 0x1Fu & (b[0] << 4 | b[1] >> 4);
    }
  } else if (width == 5) {
    switch (pos) {
    case 0: return 0x1Fu & (b[0] >> 3);
    case 1: return 0x1Fu & (b[0] >> 2);
    case 2: return 0x1Fu & (b[0] >> 1);
    case 3: return 0x1Fu & (b[0] >> 0);
    case 4: return 0x1Fu & (b[0] << 1 | b[1] >> 7);
    case 5: return 0x1Fu & (b[0] << 2 | b[1] >> 6);
    case 6: return 0x1Fu & (b[0] << 3 | b[1] >> 5);
    case 7: return 0x1Fu & (b[0] << 4 | b[1] >> 4);
    }
  }
  /* error */
  return 0xFF;
}

unsigned long
getbits(unsigned char *buf, size_t pos, size_t width)
{
}

int
main(int argc, char **argv)
{
  unsigned char *buf;
  unsigned long r;
  size_t pos, wid;
  unsigned i;
  if (argv[1] == NULL) goto help;
  pos = strtoul(argv[1], 0, 0);
  if (argv[2] == NULL) goto help;
  wid = strtoul(argv[2], 0, 0);
  buf = malloc(argc);
  if (buf == NULL) { perror("malloc"); return 1; }
  for (i = 3; argv[i]; i++) {
    buf[i - 3] = strtoul(argv[i], 0, 16);
  }
  r = getbits(buf, pos, wid);
  printf("%lx:%lx = %lx\n", (unsigned long)pos, (unsigned long)wid, r);
  return 0;
help:
  puts("usage: z pos width hex2 ...");
  return 1;
}
