; /*
; DICE-C compiler
dcc NoClick.c -r -mS -mi -proto -v -oNoClick
Quit
*/

/*
**
**  $VER: NoClick.c 1.4 (5.1.96)
**  NoClick 1.0
**
**  (C) Copyright 1994-96 by Roland 'Gizzy' Mainz
**
**
*/

/* amiga includes */
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <workbench/startup.h>
#include <workbench/icon.h>
#include <devices/trackdisk.h>

/* amiga prototypes */
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/icon_protos.h>
#include <clib/alib_protos.h>

#ifdef __DICE_INLINE
#define IntuitionBase_DECLARED 1
#define IconBase_DECLARED 1

#include <proto/exec_protos.h>
#include <proto/dos_protos.h>
#include <proto/intuition_protos.h>
#include <proto/icon_protos.h>
#endif /* __DICE_INLINE */

/* ansi includes */
#include <string.h>

/* version string */
#include "NoClick_rev.h"

/* misc defines */
#define NAME "NoClick"

/* prototypes */
#ifdef _DCC
                long                  wbmain( struct WBStartup * );
#endif /* _DCC */

                void                  chkabort( void );
                long                  main( long, STRPTR * );
        static  void                  DefaultSettings( void );
        static  void                  FreeInitProjectResult( void );
        static  void                  ReadENVPrefs( void );

        static  void                  ClearRDA( void );
        static  void                  ScanRDA( void );
        static  void                  ScanToolTypes( STRPTR * );

        static  void                  RunTool( void );

        static  BOOL                  OpenLibStuff( void );
        static  void                  CloseLibStuff( void );

        static  BOOL                  CreateBasicResources( void );
        static  void                  DeleteBasicResources( void );

                void                  AttemptOpenLibrary( struct Library **, STRPTR, STRPTR, ULONG );

                STRPTR                StringSave( STRPTR );
                void                  FreeString( STRPTR );

                APTR                  AllocVecPooled( APTR, ULONG );
                void                  FreeVecPooled( APTR, APTR );


/* version string */
STRPTR versionstring = VERSTAG;

long main_retval,
     main_retval2;

static struct RDArgs  *startuprda;

/* shared libraries */
struct Library *IntuitionBase,
               *IconBase;

/* mempool for strings */
APTR StringPool;

/* templates for ReadArgs() */
#define STARTUP_TEMPLATE "DEV=DEVICE,UNIT/N,NOCLICK=OFF/S,CLICK=ON/S,TOGGLE/S,INFO/S,QUIET=NOREQ/S"
#define ENV_TEMPLATE     "DEV=DEVICE,UNIT/N,NOCLICK=OFF/S,CLICK=ON/S,TOGGLE/S,INFO/S,QUIET=NOREQ/S"

static
struct
{
    STRPTR  devicename;
    long   *unit;
    long   *noclick;
    long   *click;
    long   *toggle;
    long   *info;
    long   *noreq;
} result;

static
struct
{
    STRPTR  devicename;
    ULONG   unit;
    BOOL    noclick;
    BOOL    click;
    BOOL    toggle;
    BOOL    info;
    BOOL    noreq;
} project;


/* disable CTRL_C break support (DICE CTRL_C abort function) */
void chkabort( void )
{
}


/* DICE workbench entry */
#ifdef _DCC
long wbmain( struct WBStartup *wbstartup )
{
    /* Call main like SAS-C */
    return( main( 0L, (STRPTR *)wbstartup ) );
}
#endif /* _DCC */


long main( long ac, STRPTR *av )
{
    LONG               numArgs,
                       x;
    struct WBStartup  *wbstartup;
    struct WBArg      *wbarg;
    struct DiskObject *tooldobj,
                      *projectdobj;
    BPTR               oldToolLock,
                       oldProjectLock;

    x = main_retval2 = 0L;
    main_retval = RETURN_OK;

    if( CreateBasicResources() )
    {
      DefaultSettings();

/* Workbench */
      if( ac == 0L )
      {
        wbstartup = (struct WBStartup *)av;

        numArgs = wbstartup -> sm_NumArgs;
        wbarg   = wbstartup -> sm_ArgList;

        if( *(wbarg[ 0 ] . wa_Name) )
        {
          if( wbarg[ 0 ] . wa_Lock )
          {
            oldToolLock = CurrentDir( (wbarg[ 0 ] . wa_Lock) );
          }

          if( tooldobj = GetDiskObjectNew( (wbarg[ 0 ] . wa_Name) ) )
          {
            /* two possible cases when started from workbench ... */
            if( numArgs < 2L )
            {
              /* ... first case, only our tool icon is given, create one project here */

              ScanToolTypes( (STRPTR *)(tooldobj -> do_ToolTypes) );

              RunTool();

              FreeInitProjectResult();
            }
            else
            {
              /* ... second case, a couple of project icons are given, multiple projects will start from here */
              for( x = 1L ; x < numArgs ; x++ )
              {
                if( wbarg[ x ] . wa_Lock )
                {
                  oldProjectLock = CurrentDir( (wbarg[ x ] . wa_Lock) );
                }

                if( *(wbarg[ x ] . wa_Name) )
                {
                  if( projectdobj = GetDiskObject( (wbarg[ x ] . wa_Name) ) )
                  {
                    ScanToolTypes( (STRPTR *)(tooldobj -> do_ToolTypes) );
                    ScanToolTypes( (STRPTR *)(projectdobj -> do_ToolTypes) );

                    RunTool();

                    FreeInitProjectResult();
                    DefaultSettings();

                    FreeDiskObject( projectdobj );
                  }
                }

                if( wbarg[ x ] . wa_Lock )
                {
                  CurrentDir( oldProjectLock );
                }
              }
            }

            FreeDiskObject( tooldobj );
          }

          if( wbarg[ 0 ] . wa_Lock )
          {
            CurrentDir( oldToolLock );
          }
        }
      }
      else
      {
/* CLI/Shell */
        if( startuprda = ReadArgs( STARTUP_TEMPLATE, (LONG *)(&result), NULL ) )
        {
          /* did we get a CTRL_C signal ? */
          if( !CheckSignal( SIGBREAKF_CTRL_C ) )
          {
            ScanRDA();

            RunTool();

            FreeInitProjectResult();
          }
          else
          {
            main_retval2 = ERROR_BREAK;
            main_retval  = RETURN_WARN;
          }

          FreeArgs( startuprda );
        }
        else
        {
          main_retval2 = IoErr();
          main_retval  = RETURN_ERROR;
        }

        PrintFault( main_retval2, NAME );
      }

      DeleteBasicResources();
    }

    SetIoErr( main_retval2 );

    return( main_retval );
}


void DefaultSettings( void )
{
    ClearRDA();

    result . devicename = TD_NAME;

    memset( (&project), 0, sizeof(project) );

    ReadENVPrefs();
}


static
void ReadENVPrefs( void )
{
    TEXT  varbuff[ 258 ];
    ULONG varlen;

    struct RDArgs envvarrda =
    {
      varbuff,
      256L,
      0L,
      0L,
      NULL,
      0L,
      NULL,
      RDAF_NOPROMPT
    };

    if( varlen = GetVar( NAME, varbuff, 256L, 0UL ) )
    {
      varbuff[ varlen ]       = '\n';
      varbuff[ (varlen + 1) ] = '\0';

      if( ReadArgs( ENV_TEMPLATE, (LONG *)(&result), (&envvarrda) ) )
      {
        ScanRDA();

        FreeArgs( (&envvarrda) );
      }
    }
}


void ClearRDA( void )
{
    memset( (&result), 0, sizeof(result) );
}


void ScanRDA( void )
{
    if( result . devicename )
    {
      FreeString( (project . devicename) );
      project . devicename = StringSave( (result . devicename) );
    }

    if( result . unit )
    {
      project . unit = (ULONG)(*(result . unit));
    }

    if( result . click )
    {
      project . click = TRUE;
    }

    if( result . noclick )
    {
      project . noclick = TRUE;
    }

    if( result . toggle )
    {
      project . toggle = TRUE;
    }

    if( result . info )
    {
      project . info = TRUE;
    }

    if( result . noreq )
    {
      project . noreq = TRUE;
    }

    ClearRDA();
}


void ScanToolTypes( STRPTR *tt )
{
    STRPTR s;

    if( s = FindToolType( tt, "DEVICENAME" ) )
      result . devicename = s;

    if( s = FindToolType( tt, "DEV" ) )
      result . devicename = s;

    if( s = FindToolType( tt, "UNIT" ) )
      StrToLong( s, (LONG *)(&(project . unit)) );

    if( s = FindToolType( tt, "NOCLICK" ) )
      result . noclick = (long *)s;

    if( s = FindToolType( tt, "OFF" ) )
      result . noclick = (long *)s;

    if( s = FindToolType( tt, "CLICK" ) )
      result . click = (long *)s;

    if( s = FindToolType( tt, "ON" ) )
      result . click = (long *)s;

    if( s = FindToolType( tt, "TOGGLE" ) )
      result . toggle = (long *)s;

    if( s = FindToolType( tt, "INFO" ) )
      result . info = (long *)s;

    if( s = FindToolType( tt, "QUIET" ) )
      result . noreq = (long *)s;

    if( s = FindToolType( tt, "NOREQ" ) )
      result . noreq = (long *)s;

    ScanRDA();
}


static
void FreeInitProjectResult( void )
{
    FreeString( (project . devicename) );
}


BOOL CreateBasicResources( void )
{
    if( OpenLibStuff() )
    {
      if( StringPool = CreatePool( MEMF_PUBLIC, 1024UL, 1024UL ) )
      {
        return( TRUE );

#ifdef COMMENTED_OUT
        DeletePool( StringPool );
#endif /* COMMENTED_OUT */
      }

      CloseLibStuff();
    }

    return( FALSE );
}


void DeleteBasicResources( void )
{
    DeletePool( StringPool );
    CloseLibStuff();
}


BOOL OpenLibStuff( void )
{
    IconBase = NULL;

    if( IntuitionBase = OpenLibrary( "intuition.library", 39UL ) )
    {
      /* mmh, this looks not very necessary, but AttemptOpenLibrary
       * will be usefull when using OpenLibrary for disked based
       * shared libraries like locale.library etc.
       */
      AttemptOpenLibrary( (&IconBase), NAME, ICONNAME, 37UL );

      if( IconBase )
      {
        return( TRUE );
      }
    }

    CloseLibStuff();

    return( FALSE );
}


void CloseLibStuff( void )
{
    CloseLibrary( IconBase );
    CloseLibrary( IntuitionBase );
}


void AttemptOpenLibrary( struct Library **library, STRPTR title, STRPTR libname, ULONG libversion )
{
    struct EasyStruct LibNotFoundES =
    {
      sizeof(struct EasyStruct),
      0UL,
      title,
      "%s\nnot found.",
      "Retry|Cancel"
    };

    struct EasyStruct LibWrongVersionES =
    {
      sizeof(struct EasyStruct),
      0UL,
      title,
      "Requires at least\n%s version %lu",
      "Cancel"
    };

    if( (*library) == NULL )
    {
      for( ;; )
      {
        /* attemp to open shared library */
        (*library) = OpenLibrary( libname, 0UL );

        if( (*library) )
        {
          /* check if we got at least "libversion" version of shared library */
          if( ((*library) -> lib_Version) < libversion )
          {
            (void)EasyRequest( NULL, (&LibWrongVersionES), 0UL, libname, libversion );

            CloseLibrary( (*library) );
            (*library) = NULL;
          }

          break;
        }

        /* prompt the user */
        if( EasyRequest( NULL, (&LibNotFoundES), 0UL, libname ) == 0L )
        {
          /* user canceled */
          break;
        }
      }
    }
}


STRPTR StringSave( STRPTR s )
{
    STRPTR saved;

    if( s )
    {
      if( saved = (STRPTR)AllocVecPooled( StringPool, (strlen( s ) + 2UL) ) )
      {
        strcpy( saved, s );

        return( saved );
      }
    }

    return( NULL );
}


void FreeString( STRPTR s )
{
    FreeVecPooled( StringPool, s );
}


APTR AllocVecPooled( APTR poolheader, ULONG memsize )
{
    ULONG *memory;

    memsize += sizeof(ULONG);

    if( memory = (ULONG *)AllocPooled( poolheader, memsize ) )
    {
      *memory = memsize;

      memory++;
    }

    return( (APTR)memory );
}


void FreeVecPooled( APTR poolheader, APTR mem )
{
    ULONG *memory;

    if( mem )
    {
      memory = (ULONG *)mem;

      memory--;

      FreePooled( poolheader, memory, (*memory) );
    }
}


void RunTool( void )
{
    struct IOExtTD        *diskreq;
    struct MsgPort        *diskport;
    struct TDU_PublicUnit *diskunit;

    diskunit = NULL; /* Used to detect if OpenDevice() fails */

    struct EasyStruct CantOpenDeviceES =
    {
      sizeof(struct EasyStruct),
      0UL,
      NAME,
      "Cant open %s\n"
      "unit %lu.",
      "Retry|Cancel"
    };

    struct EasyStruct ClickInfoES =
    {
      sizeof(struct EasyStruct),
      0UL,
      NAME,
      "%s\n"
      "unit %lu\n"
      "has noclick flag %sset.",
      "Ok"
    };

    if( diskport = CreateMsgPort() )
    {
      if( diskreq = (struct IOExtTD *)CreateExtIO( diskport, (ULONG)sizeof(struct IOExtTD) ) )
      {
        /* loop until the device could be opened or user cancels CantOpenDeviceES */
        for( ;; )
        {
          if( OpenDevice( (project . devicename), (project . unit), (struct IORequest *)diskreq, TDF_ALLOW_NON_3_5 ) == (BYTE)0 )
          {
            diskunit = (struct TDU_PublicUnit *)(diskreq -> iotd_Req . io_Unit);

            Forbid();

            if( ((project . click) || (project . noclick)) )
            {
              /* check if user set (project . click) OR (project . noclick),
               * NOT both
               */
              if( !((project . click) && (project . noclick)) )
              {
                if( project . click )
                {
                  /* clear noclick flag */
                  (diskunit -> tdu_PubFlags) &= ~TDPF_NOCLICK;
                }

                if( project . noclick )
                {
                  /* set noclick flag */
                  (diskunit -> tdu_PubFlags) |= TDPF_NOCLICK;
                }
              }
            }
            else
            {
              if( project . toggle )
              {
                /* toggle noclick flag */
                (diskunit -> tdu_PubFlags) ^= TDPF_NOCLICK;
              }
            }

            Permit();

            if( project . info )
            {
              STRPTR ClickSet;

              Forbid();

                ClickSet = ((((diskunit -> tdu_PubFlags) & TDPF_NOCLICK))?(""):("not "));

              Permit();

              if( Cli() )
              {
                Printf( "\"%s\" unit %lu has noclick flag %sset.\n", (project . devicename), (project . unit), ClickSet );
              }
              else
              {
                EasyRequest( NULL, (&ClickInfoES), NULL, (project . devicename), (project . unit), ClickSet );
              }
            }

            CloseDevice( (struct IORequest *)diskreq );

            break;
          }
          else
          {
            if( project . noreq )
            {
              break;
            }
            else
            {
              if( EasyRequest( NULL, (&CantOpenDeviceES), NULL, (project . devicename), (project . unit) ) == 0L )
              {
                /* user canceled */
                break;
              }
            }
          }
        }

        if( diskunit == NULL )
        {
          main_retval2 = ERROR_OBJECT_NOT_FOUND;
          main_retval  = RETURN_ERROR;
        }

        DeleteExtIO( (struct IORequest *)diskreq );
      }
      else
      {
        /* Can't create IOExtTD */
        main_retval2 = ERROR_NO_FREE_STORE;
        main_retval  = RETURN_FAIL;
      }

      DeleteMsgPort( diskport );
    }
    else
    {
      /* Can't create msgport */
      main_retval2 = ERROR_NO_FREE_STORE;
      main_retval  = RETURN_FAIL;
    }
}


