#include <stdio.h>
#include "Error.h"
#include "Connect.h"
#include "Code.h"
#include <netinet/in.h>

Trap expand();

Trap literal_GetString(), literal_PutString(),
     literal_GetMemory(), literal_PutMemory(),
     literal_GetCard16(), literal_PutCard16(),
     literal_GetCard32(), literal_PutCard32();

CodeDomain literal =
{
  "literal",
  literal_GetString,
  literal_PutString,
  literal_GetMemory,
  literal_PutMemory,
  literal_GetCard16,
  literal_PutCard16,
  literal_GetCard32,
  literal_PutCard32
};

/*
 * ERRORS:
 *
 * PROTO_PACKETTOOSHORT: FATAL
 * The protocol claimed the packet was longer than what was received.
 *
 * PROTO_ENDPACKET: FATAL
 * The packet received was too short to contain the requested item (%d).
 *
 * PROTO_MISMATCH: FATAL
 * The protocol of the packet did not match.
 */

Trap literal_GetString(block, string)
     CodeBlock *block;
     char **string;
{
  char *s;

  s = block->current;
  while (s - block->data < block->dataSize && *s != '\0') s++;

  if (s - block->data == block->dataSize)
    Return(PROTO_ENDPACKET, -1);

  *string = block->current;
  block->current = s + 1;
  return OK;
}

Trap literal_PutString(block, string)
     CodeBlock *block;
     char *string;
{
  char *s;
  int offset;

  if (string == NULL)
    Return(GENERAL_NULLPOINTER, NULL);

  s = block->current;

  if (s - block->data + strlen(string) + 1 > block->dataSize)
    {
      offset = s - block->data;
      if (Code_Expand(block, strlen(string) + 1))
	return CHECK;
      s = block->data + offset;
    }

  while (*string != '\0')
    *s++ = *string++;

  *s++ = '\0';
  block->current = s;

  return OK;
}

Trap literal_GetMemory(block, memory, size)
     CodeBlock *block;
     char **memory;
     Card32 *size;
{
  if (literal_GetCard32(block, size))
    return CHECK;

  if (block->current + *size > block->data + block->dataSize)
    Return(PROTO_ENDPACKET, *size);

  *memory = block->current;
  block->current += *size;

  return OK;
}

Trap literal_PutMemory(block, memory, size)
     CodeBlock *block;
     char *memory;
     Card32 size;
{
  char *s;
  int offset;

  if (memory == NULL)
    Return(GENERAL_NULLPOINTER, NULL);

  if (literal_PutCard32(block, size))
    return CHECK;

  s = block->current;

  if (s - block->data + size > block->dataSize)
    {
      offset = s - block->data;
      if (Code_Expand(block, size))
	return CHECK;
      s = block->data + offset;
    }

  memcpy(s, memory, size);
  block->current += size;

  return OK;
}

Trap literal_GetCard16(block, card)
     CodeBlock *block;
     Card16 *card;
{
  char *s;

  s = block->current;
  if ((int)(s) & 1) s++;		/* auto padding */

  if (s - block->data + 2 > block->dataSize)
    Return(PROTO_ENDPACKET, 2);

  *card = ntohs(*(Card16 *)s);
  block->current = s + 2;
  return OK;
}

/*
Trap literal_PutCard16(CodeBlock *block, Card16 card)
*/
Trap literal_PutCard16(block, card)
     CodeBlock *block;
     Card16 card;
{
  char *s;
  int offset;

  s = block->current;
  if ((int)(s) & 1) s++;		/* auto padding */

  if (s - block->data + 2 > block->dataSize)
    {
      offset = s - block->data;
      if (Code_Expand(block, 0))
	return CHECK;
      s = block->data + offset;
    }

  *(Card16 *)s = htons(card);
  block->current = s + 2;
  return OK;
}

Trap literal_GetCard32(block, card)
     CodeBlock *block;
     Card32 *card;
{
  char *l;

  l = block->current;
  if ((int)(l) & 3) l += 4 - ((int)(l) & 3);	/* auto padding */

  if (l - block->data + 4 > block->dataSize)
    Return(PROTO_ENDPACKET, 4);

  *card = ntohl(*(Card32 *)l);
  block->current = l + 4;
  return OK;
}

Trap literal_PutCard32(block, card)
     CodeBlock *block;
     Card32 card;
{
  Trap retval;
  char *l;
  int offset;

  l = block->current;
  if ((int)(l) & 3) l += 4 - ((int)(l) & 3);	/* auto padding */

  if (l - block->data + 4 > block->dataSize)
    {
      offset = l - block->data;
      if (Code_Expand(block, 0))
	return CHECK;
      l = block->data + offset;
    }

  *(Card32 *)l = htonl(card);
  block->current = l + 4;
  return OK;
}
