#ifndef lint
static char *RCSid = "$Id:$";
#endif

/*
 *  The Regina Rexx Interpreter
 *  Copyright (C) 1992-1994  Anders Christensen <anders@pvv.unit.no>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "rexx.h"

#include <assert.h>
#include <string.h>
#include <ctype.h>


#define OPTION(opt) { #opt, EXT_##opt, NULL }
#define METAOP(name,value) { #name, -1, value }


struct option all_options[] = {  /* Must be alphabetically sorted! */
   METAOP( BUFFERS, "BUFTYPE_BIF DESBUF_BIF DROPBUF_BIF MAKEBUF_BIF" ),
   OPTION( BUFTYPE_BIF ),
   OPTION( CACHEEXT ),
   OPTION( CLOSE_BIF ),
   OPTION( DESBUF_BIF ),
   OPTION( DROPBUF_BIF ),
   METAOP( FILEIO, "OPEN_BIF CLOSE_BIF" ),
   OPTION( FIND_BIF ),
   OPTION( FLUSHSTACK ), 
   OPTION( LINEOUTTRUNC ),
   OPTION( MAKEBUF_BIF ),
   OPTION( OPEN_BIF ),
   OPTION( PRUNE_TRACE ),
   { NULL, 0 }
} ;


void do_options( streng *options, int toggle )
{
   char *cptr=NULL, *eptr=NULL, *start=NULL ;
   int length=0, inverse=0, tmp=0, obyte=0, obit=0 ;
   struct option *lower=NULL, *upper=NULL, *middle=NULL ;

#ifndef NDEBUG
   {
      static int didtest=0 ;

      if (!didtest)
      {
         struct option *current ;
         int i, old, new ;

         didtest=1 ;
         assert( sizeof(all_options)>1 ) ;
         for (current=all_options+1; current->name; current++ ) 
            assert(strcmp(current->name,(current-1)->name)>0) ;

#define CHECK_IT(AA,aa) if (current->offset==EXT_##AA) { \
	old=((currlevel->u.flags[EXT_##AA/8]>>(7-(EXT_##AA%8))) & 0x01); \
	currlevel->u.options.aa ^= 1; \
	new=((currlevel->u.flags[EXT_##AA/8]>>(7-(EXT_##AA%8))) & 0x01); \
	assert(old!=new); currlevel->u.options.aa ^= 1; } i++ ;

         for (current=all_options; current->name; current++)
         {
            i = 0 ;
            CHECK_IT( OPEN_BIF,		open_bif ) ;
            CHECK_IT( CLOSE_BIF,	close_bif ) ;
            CHECK_IT( FIND_BIF,		find_bif ) ;
            CHECK_IT( CACHEEXT, 	cacheext ) ;
            CHECK_IT( MAKEBUF_BIF,	makebuf_bif ) ;
            CHECK_IT( DROPBUF_BIF,	dropbuf_bif ) ;
            CHECK_IT( DESBUF_BIF,	desbuf_bif ) ;
            CHECK_IT( BUFTYPE_BIF,	buftype_bif ) ;
            CHECK_IT( FLUSHSTACK,	flushstack ) ;
            CHECK_IT( LINEOUTTRUNC,	lineouttrunc ) ;
            CHECK_IT( PRUNE_TRACE,      prune_trace ) ;
         /* assert( i == (sizeof(all_options)/sizeof(struct option))-1 ) ; */
         }
      }
   }

#endif /* NDEBUG */

   cptr = options->value ;
   eptr = cptr + options->len ;

   while (cptr<eptr)
   {
      for (;cptr<eptr && isspace(*cptr); cptr++) ;
      for (start=cptr; cptr<eptr && !isspace(*cptr); cptr++ ) 
         *cptr = toupper( *cptr ) ;

      if ((inverse=(*start=='N' && *(start+1)=='O') && cptr>start+2))
         start += 2 ;

      length = cptr - start ;

      lower = all_options ;
      upper = lower + (sizeof(all_options)/sizeof(struct option)) - 2 ;

      while( upper >= lower )
      {
         middle = lower + (upper-lower)/2 ;
         tmp = strncmp(middle->name,start,length) ;
         if (tmp==0 && middle->name[length]==0x00) 
            break ;

         if (tmp>0)
            upper = middle - 1 ;
         else
            lower = middle + 1 ;
      }

      /* If option is unknown, don't care ... */
      if ( upper >= lower )
      { 
         assert ( middle->name ) ;
         if (middle->offset == -1)
         {
            do_options( Str_cre(middle->contains), toggle^inverse ) ; 
         }
         else
         {
            obyte = middle->offset/(sizeof(unsigned char)*8) ;
            obit = middle->offset - obyte*(sizeof(unsigned char)*8) ;
            if (inverse^toggle)
               currlevel->u.flags[obyte] &= ~(1<<(7-obit)) ;
            else
               currlevel->u.flags[obyte] |= (1<<(7-obit)) ;
         }
      }
   }
   Free_string( options ) ;
}





