/* eatest.c (emx+gcc) */

#define INCL_DOSFILEMGR
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <io.h>
#include <sys/ea.h>

#define FALSE 0
#define TRUE  1

enum actions
{
  ACTION_NONE,
  ACTION_ADD,
  ACTION_SHOW,
  ACTION_REMOVE
};

static enum actions action = ACTION_NONE;


static void do_add (const char *path, const char *name, const char *value)
{
  int i, size;
  struct _ea ea;
  char *buf;

  size = strlen (value);
  buf = malloc (size + 4);
  if (buf == NULL)
    {
      fprintf (stderr, "Out of memory\n");
      exit (2);
    }
  ((USHORT *)buf)[0] = EAT_ASCII;
  ((USHORT *)buf)[1] = size;
  memcpy (buf+4, value, size);
  ea.flags = 0;
  ea.size = size + 4;
  ea.value = buf;
  if (strcmp (path, "-") == 0)
    i = _ea_put (&ea, NULL, fileno (stdout), name);
  else
    i = _ea_put (&ea, path, 0, name);
  if (i < 0)
    {
      perror (path);
      exit (2);
    }
  free (buf);
}


static void do_remove (const char *path, const char *name)
{
  int i;

  if (strcmp (path, "-") == 0)
    i = _ea_remove (NULL, fileno (stdout), name);
  else
    i = _ea_remove (path, 0, name);
  if (i < 0)
    perror (path);
}


static void do_show (const char *path, const char *name)
{
  struct _ea ea;
  int i;

  if (strcmp (path, "-") == 0)
    i = _ea_get (&ea, NULL, fileno (stdin), name);
  else
    i = _ea_get (&ea, path, 0, name);
  if (i < 0)
    perror (path);
  else
    {
      printf ("%s: %s: ", path, name);
      if (ea.size >= 4)
        {
          switch (*(USHORT *)ea.value)
            {
            case EAT_ASCII:
              printf ("\"");
              fwrite (ea.value+4, ea.size-4, 1, stdout);
              printf ("\"\n");
              break;
            case EAT_BINARY:
              printf ("%d bytes of binary data\n", ea.size);
              break;
            case EAT_BITMAP:
              printf ("%d bytes of bitmap data\n", ea.size);
              break;
            case EAT_METAFILE:
              printf ("%d bytes of metafile data\n", ea.size);
              break;
            case EAT_ICON:
              printf ("%d bytes of icon data\n", ea.size);
              break;
            case EAT_EA:
              printf ("%d bytes of associated data\n", ea.size);
              break;
            case EAT_MVMT:
            case EAT_MVST:
            case EAT_ASN1:
              printf ("%d bytes of multivalue data\n", ea.size);
              break;
            default:
              printf ("%d bytes\n", ea.size);
              break;
            }
        }
      else
        printf ("%d bytes\n", ea.size);
      _ea_free (&ea);
    }
}


static void usage (void)
{
  fputs ("Usage: eatest -s <file> <name>\n", stderr);
  fputs ("       eatest -a <file> <name> <value>\n", stderr);
  fputs ("       eatest -r <file> <name>\n", stderr);
  fputs ("Options:\n", stderr);
  fputs ("  -s   Show extended attribute\n", stderr);
  fputs ("  -a   Add extended attribute\n", stderr);
  fputs ("  -r   Remove extended attribute\n", stderr);
  exit (1);
}


static void set_action (enum actions a)
{
  if (action != ACTION_NONE)
    usage ();
  action = a;
}


int main (int argc, char *argv[])
{
  int c;

  opterr = FALSE;
  while ((c = getopt (argc, argv, "ars")) != EOF)
    {
      switch (c)
        {
        case 'a':
          set_action (ACTION_ADD);
          break;
        case 'r':
          set_action (ACTION_REMOVE);
          break;
        case 's':
          set_action (ACTION_SHOW);
          break;
        default:
          usage ();
        }
    }
  switch (action)
    {
    case ACTION_ADD:
      if (argc - optind != 3)
        usage ();
      do_add (argv[optind+0], argv[optind+1], argv[optind+2]);
      break;
    case ACTION_REMOVE:
      if (argc - optind != 2)
        usage ();
      do_remove (argv[optind+0], argv[optind+1]);
      break;
    case ACTION_SHOW:
      if (argc - optind != 2)
        usage ();
      do_show (argv[optind+0], argv[optind+1]);
      break;
    default:
      usage ();
    }
  return (0);
}
