/*   ---------------------------------      -------     
 *   |\  | | | | |  |.| |   \|  |/ /|\      |||||||     
 *   | | | |/  | |\ |/  |/|  |\ |/  |    ?  ---+---  =< 
 *   | | | |   | |  |     |  |  |   |     \qqqqqqqqq/   
 *   ---------------------------------  ~~~~~~~~~~~~~~~~
 *  TestBits - tests whether one or more protection flags are set.
 *  Copyright (C) 1993 Torsten Poulin
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  The author can be contacted by s-mail at
 *    Torsten Poulin
 *    Banebrinken 99, 2, 77
 *    DK-2400 Copenhagen NV
 *    DENMARK
 *
 * $Id: TestBits.c,v 37.1 93/03/11 17:33:47 Torsten Rel $
 * $Log:	TestBits.c,v $
 * Revision 37.1  93/03/11  17:33:47  Torsten
 * Initial revision.
 * 
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#ifdef __SASC
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#endif
#include "tastlib.h"
#include "testbits_rev.h"

#define PROGNAME "TestBits"
#define TEMPLATE "NAME/A,FLAGS/A"
#define OPT_NAME  0
#define OPT_FLAGS 1

char const versionID[] = VERSTAG;
char const copyright[] = "$COPYRIGHT:Copyright © 1993 Torsten Poulin$";

typedef struct {
  struct DosLibrary *DOSBase;
  struct FileInfoBlock fib;
} Global;

LONG setbit(UBYTE c, LONG *mask, Global *global);
LONG matchflags(UBYTE *name, UBYTE *flags, Global *global);


LONG entrypoint(VOID)
{
  struct DosLibrary *DOSBase;
  struct RDArgs *args;
  Global *global;
  LONG arg[2];
  LONG rc = RETURN_OK;

  if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
    return RETURN_FAIL;

  if (!(global = AllocVec(sizeof(Global), MEMF_PUBLIC | MEMF_CLEAR)))
    rc = ERROR_NO_FREE_STORE;
  else
  {
    global->DOSBase = DOSBase;

    arg[OPT_NAME] = arg[OPT_FLAGS] = 0L;
    
    if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
      rc = RETURN_ERROR;
    else
    {
      rc = matchflags((UBYTE *) arg[OPT_NAME],
		      (UBYTE *) arg[OPT_FLAGS], global);
      FreeArgs(args);
    }
    FreeVec(global);
  }
  rc = printErrorMsg(rc, PROGNAME, DOSBase);
  CloseLibrary((struct Library *) DOSBase);
  return rc;
}


LONG matchflags(UBYTE *name, UBYTE *flags, Global *global)
{
  struct DosLibrary *DOSBase = global->DOSBase;
  LONG setmask = 0L;
  LONG unsetmask = 0L;
  LONG bits = 0L;
  BPTR lock;
  LONG rc = RETURN_OK;

  for (; *flags; flags++)
  {
    if (*flags == '-')
    {
      if (*++flags)
	rc = setbit(*flags, &unsetmask, global);
      /* Silently ignore a trailing '-' */ 
    }
    else
      rc = setbit(*flags, &setmask, global);
  }

  if (rc == RETURN_OK)
  {
    if (setmask & unsetmask)
    {
      MyPrintf(global, "%s: Ambiguous flag specification\n", PROGNAME);
      rc = RETURN_ERROR;
    }
    else
    {
      if (!(lock = Lock(name, SHARED_LOCK)))
	rc = RETURN_ERROR;
      else
      {
	if (!Examine(lock, &global->fib))
	{
	  MyPrintf(global, "%s: Cannot examine \"%s\"\n", PROGNAME, name);
	  rc = RETURN_ERROR;
	}
	else	    
	{
	  bits = global->fib.fib_Protection;
	  /* Flip the lower 4 bits and get rid of the higher 24... */
	  bits = (~bits & 0x0000000f) | (bits & 0x000000f0);
	  rc = ((bits & setmask) == setmask && (bits & unsetmask) == 0L
		? RETURN_OK
		: RETURN_WARN);
	}
	UnLock(lock);
      }
    }
  }
  return rc;
}


LONG setbit(UBYTE c, LONG *mask, Global *global)
{
  c |= 0x20; /* to lower case (ought to be: c = tolower(c); */
  switch (c)
  {
  case 's': *mask |= FIBF_SCRIPT;  break;
  case 'p': *mask |= FIBF_PURE;    break;
  case 'a': *mask |= FIBF_ARCHIVE; break;
  case 'r': *mask |= FIBF_READ;    break;
  case 'w': *mask |= FIBF_WRITE;   break;
  case 'e': *mask |= FIBF_EXECUTE; break;
  case 'd': *mask |= FIBF_DELETE;  break;
  default:
    MyPrintf(global, "%s: Unknown protection flag\n", PROGNAME);
    return RETURN_ERROR;
  }
  return RETURN_OK;
}
