AwakeMUD-0.8.18B/
AwakeMUD-0.8.18B/doc/
AwakeMUD-0.8.18B/lib/
AwakeMUD-0.8.18B/lib/etc/
AwakeMUD-0.8.18B/lib/etc/pfiles/
AwakeMUD-0.8.18B/lib/misc/
AwakeMUD-0.8.18B/lib/text/
AwakeMUD-0.8.18B/lib/text/help/
AwakeMUD-0.8.18B/lib/text/wizhelp/
AwakeMUD-0.8.18B/lib/veh/
AwakeMUD-0.8.18B/lib/world/
AwakeMUD-0.8.18B/lib/world/mob/
AwakeMUD-0.8.18B/lib/world/mtx/
AwakeMUD-0.8.18B/lib/world/qst/
AwakeMUD-0.8.18B/lib/world/shp/
AwakeMUD-0.8.18B/lib/world/veh/
// file: bitfield.cpp
// author: Andrew Hynek
// contents: implementation of the Bitfield class

#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#include "bitfield.h"
#include "structs.h"
#include "utils.h"

// ______________________________
//
// static vars
// ______________________________

static const int NUM_BUFFERS = 8;
// I wish I could use (Bitfield::TotalWidth()+1), but that's not allowed..
static const int BUFFER_SIZE = 256;
static char buffer_tab[NUM_BUFFERS][BUFFER_SIZE];
static int  buffer_idx = 0;
static const int LOOP_BREAK = 100;

// ______________________________
//
// Bitfield()
// ______________________________

Bitfield::Bitfield()
{
  Clear();
}

Bitfield::Bitfield(dword offset)
{
  Clear();
  SetBit(offset);
}

// ______________________________
//
// testing funcs
// ______________________________

bool Bitfield::IsSet(dword offset) const
{
  const int idx = offset / bits_per_var;
  const int flag = offset % bits_per_var;

  return (data[idx] & (1 << flag));
}

bool Bitfield::AreAnySet(dword one, ...) const
{
  va_list arg_list;
  dword offset;

  if (one == ENDBIT)
    return false;

  if (IsSet(one))
    return true;

  va_start(arg_list, one);

  while (true) {
    offset = va_arg(arg_list, dword);

    if (offset == ENDBIT) {
      va_end(arg_list);
      return false;
    } else if (IsSet(offset)) {
      va_end(arg_list);
      return true;
    }
  }
}

int  Bitfield::GetNumSet() const
{
  int count = 0;

  for (int i = 0; i < TotalWidth(); i++)
    if (IsSet(i))
      count++;

  return count;
}

bool Bitfield::AreAnyShared(const Bitfield &test) const
{
  for (int i = 0; i < TotalWidth(); i++)
    if (IsSet(i) && test.IsSet(i))
      return true;

  return false;
}

int  Bitfield::GetNumShared(const Bitfield &test) const
{
  int count = 0;

  for (int i = 0; i < BITFIELD_SIZE; i++)
    for (int j = 0; j < bits_per_var; j++) {
      const int flag = 1 << j;

      if ((test.data[i] & flag) && (this->data[i] & flag))
        count++;
    }

  return count;
}

bool Bitfield::operator==(const Bitfield &two) const
{
  return (memcmp(data, two.data, BITFIELD_SIZE*sizeof(bitfield_t)) == 0);
}

bool Bitfield::operator!=(const Bitfield &two) const
{
  return (memcmp(data, two.data, BITFIELD_SIZE*sizeof(bitfield_t)) != 0);
}

void Bitfield::Clear()
{
  memset(data, 0, BITFIELD_SIZE*sizeof(bitfield_t));
}

void Bitfield::SetBit(dword offset)
{
  const int idx = offset / bits_per_var;
  const int flag = offset % bits_per_var;

  data[idx] |= (1 << flag);
}

void Bitfield::SetBits(dword one, ...)
{
  va_list arg_list;
  dword offset;

  if (one == ENDBIT)
    return;

  SetBit(one);

  va_start(arg_list, one);

  while (true) {
    offset = va_arg(arg_list, dword);

    if (offset != ENDBIT)
      SetBit(offset);
    else
      break;
  }

  va_end(arg_list);
}

void Bitfield::SetAll(const Bitfield &two)
{
  for (int i = 0; i < TotalWidth(); i++)
    if (two.IsSet(i) && i > 0)
      SetBit(i);
}

void Bitfield::RemoveBit(dword offset)
{
  const int idx = offset / bits_per_var;
  const int flag = offset % bits_per_var;

  data[idx] &= ~(1 << flag);
}

void Bitfield::RemoveBits(dword one, ...)
{
  va_list arg_list;
  dword offset;

  if (one == ENDBIT)
    return;

  RemoveBit(one);

  va_start(arg_list, one);

  while (true) {
    offset = va_arg(arg_list, dword);

    if (offset != ENDBIT)
      RemoveBit(offset);
    else
      break;
  }

  va_end(arg_list);
}

void Bitfield::RemoveAll(const Bitfield &two)
{
  for (int i = 0; i < TotalWidth(); i++)
    if (IsSet(i) && two.IsSet(i))
      RemoveBit(i);
}

void Bitfield::ToggleBit(dword offset)
{
  const int idx = offset / bits_per_var;
  const int flag = offset % bits_per_var;

  data[idx] ^= (1 << flag);
}

void Bitfield::ToggleBits(dword one, ...)
{
  va_list arg_list;
  dword offset;

  if (one == ENDBIT)
    return;

  ToggleBit(one);

  va_start(arg_list, one);

  while (true) {
    offset = va_arg(arg_list, dword);

    if (offset != ENDBIT)
      ToggleBit(offset);
    else
      break;
  }

  va_end(arg_list);
}

const char *Bitfield::ToString() const
{
  char *buffer = buffer_tab[buffer_idx];
  char *buf_ptr = buffer;

  if (++buffer_idx >= NUM_BUFFERS)
    buffer_idx = 0;

  for (int i = TotalWidth()-1; i >= 0; i--)
    if (IsSet(i))
      *(buf_ptr++) = '1';
    else if (buf_ptr != buffer)
      *(buf_ptr++) = '0';

  if (buf_ptr == buffer) {
    // if no flags were set, just set it to "0":
    strcpy(buffer, "0");
  } else
    *buf_ptr = '\0';

  return (const char *)buffer;
}

void Bitfield::FromString(const char *str)
{
  const size_t len = strlen(str);
  dword offset = 0;

  Clear();

  if (!len)
    return;

  const char *str_ptr = str + len - 1;

  while (true) {
    if (*str_ptr != '0')
      SetBit(offset);

    // if we're already at the beginning of the string, break
    if (str_ptr == str)
      break;
    str_ptr--;

    // if we can't hold any more bits, just break
    if (++offset >= ENDBIT)
      break;
  }
}

void Bitfield::PrintBits(char *dest, size_t dest_size,
                         const char *names[], size_t name_cnt)
{
  size_t len = 0;
  int left = dest_size - 1;
  bool first = true;

  *dest = '\0';

  for (int i = 0; i < TotalWidth() && left > 0; i++)
    if (IsSet(i)) {
      size_t written;

      if ((unsigned)i < name_cnt && *names[i] != '\n')
        written = snprintf(dest + len, left,
                           "%s%s", first? "" : ", ", names[i]);
      else
        written = snprintf(dest + len, left,
                           "%sUNDEFINED", first? "" : ", ");

      left -= written;
      len += written;

      if (first)
        first = false;
    }

  if (left < 1) {
    strncpy(dest, "<TRUNCATED>", dest_size);
    len = MIN(dest_size-1, 11);
  }

  *(dest+len) = '\0';
}