/******************************************************************************

    MODUL
	flags.c

    DESCRIPTION
	lowlevel flags-support for DME/XDME

    NOTES
	is used by vars.c

    BUGS
	<none known>

    TODO
	-/-

    EXAMPLES
	-/-

    SEE ALSO
	vars.c

    INDEX

    HISTORY
	<see RCS-File>


******************************************************************************/

/*
**  (C)Copyright 1992 by Bernd Noll for null/zero-soft
**  All Rights Reserved
**
**  RCS Header: $Id: flags.c,v 1.65 92/11/09 12:47:21 b_noll Exp $
**
**  Basic Functions to work with (arrays of) DME-Flags
**  (both Local and Global Flags use these functions)
**
**  Put together to start a little bit of modularisation
**  in the sources.
*/

/**************************************
		Includes
**************************************/
#include "defs.h"


/**************************************
	    Globale Exports
**************************************/
Prototype int	 test_arg  (char*, int);
Prototype char * GetFlag   (char*, char*, int, char*);
Prototype char	 SetFlag   (char*, char*, char*, int, char*);
Prototype int	 IsFlagSet (char*, int, int);


/**************************************
      Interne Defines & Strukturen
**************************************/
static const UBYTE bit[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };


/*
 *  test_arg  (previous toggler)
 *
 *  simple hack do be used if you wanna implement
 *  a function which can regognize on/off/toggle for
 *  a BOOL (boolean) variable
 *  args: 1 == TRUE == set == on | 0 == FALSE == reset == off | toggle == switch
 */

int test_arg (char * str, int bool)
{
    if (str)
    {
	switch(str[0])
	{  /* --- it would be much more senseful to switch with (str[0]&31)<<5|(str[1]&31) */
	case '0':               /* 0 */
	case 'R':               /* Reset */
	case 'r':               /* reset */
	case 'F':               /* FALSE */
	case 'f':               /* false */
	    return(0);

	case '1':               /* 1 */
	    return(1);

	case 'S':               /* Set/Switch */
	case 's':               /* set/switch */
	    switch (str[1] | 32)
	    {
	    case 'e':           /* set */
		return(1);

	    case 'w':           /* switch */
		return(!bool);

	    default:
		abort(bool);

	    } /* switch */

	case 'T':               /* Toggle/True */
	case 't':               /* toggle/true */
	    switch (str[1] | 32)
	    {
	    case 'r':           /* true */
		return(1);

	    case 'o':           /* toggle */
		return(bool ? 0 : 1);

	    default:
		abort(bool);

	    } /* switch */

	case 'O':               /* on / off */
	case 'o':               /* on / off */
	    switch(str[1] | 32)
	    {
	    case 'n':           /* on */
		return(1);

	    case 'f':           /* off */
		return(0);

	    default:
		abort(bool);

	    } /* switch */

	default:		/* unexpected value */
	    abort (bool);
	} /* switch */
    } else
    {			 /* unexpected value */
	abort(bool);
    } /* if */
} /* test_arg */



int IsFlagSet (char * toggles, int number, int max)
{
    if (number < 0 || number >= max)
    {
	abort(0);
    } /* if */

    return((toggles[number/8] & bit[number&7]) ? 1 : 0);
} /* IsFlagSet */



/*
 * if the string in name matches the format <xy><num>
 *  <xy>  eq identifier
 *  <num> /N in [0..max]
 * then the flag <num> in toggles is set according to value
 */

char SetFlag (char * toggles, char * name, char * value, int max, char * identifier)
{
    int num;
    int idlen = strlen(identifier);

    if (strncmp(name,identifier,idlen))
    { /* invalid name */
	return(0);
    } /* if */
    name += idlen;

    if (!is_number(name))
    {		  /* invalid name */
	return(0);
    } /* if */

    num = atoi(name);
    if (num < 0 || num >= max )
    {
	abort(1);
    } /* if */

    {
	char res;
	char bn = num & 7;
	num	= num / 8;
	res	= test_arg(value, toggles[num] & bit[bn]);
	toggles[num] = (toggles[num] & ~bit[bn]) | (res ? bit[bn] : 0);  /* shorter: (res * bit[bn]) */
    } /* block */

    return(1);
} /* SetFlag */



/*
 * if the string in name matches the format <xy><num>
 *  <xy>  eq identifier
 *  <num> /N in [0..max]
 * then a string is allocated and filled according to flag <num> in toggles
 */

char * GetFlag(char * toggles, char * name, int max, char * identifier)
{
    int num;
    int idlen = strlen(identifier);
    char* str;

    if (strncmp(name, identifier, idlen))
    { /* invalid name */
	return(NULL);
    } /* if */
    name += idlen;

    if (!is_number(name))
    {		  /* invalid name */
	return(NULL);
    } /* if */

    num = atoi(name);
    if (num < 0 || num >= max )
    {
	abort(NULL);
    } /* if */

    if (!(str = malloc(2)))
    {
	nomemory();
	abort(NULL);
    } /* if */

    sprintf(str, "%d", IsFlagSet(toggles, num, max), 0);

    return(str);
} /* GetFlag */


/******************************************************************************
*****  ENDE flags.c
******************************************************************************/

