/*-------------------------------------------------------------------------
--
-- MPATCH.C
-- 
-- A small utility that patches a MonitorSpec's BeamCon0 field in order
-- to fix the sync polarity. Some monitors, like the Commodore 1960,
-- need other than negative syncs to determine the picture's aspect.
--
-- author: Gregor S. M. Kuhlmann
--
-- revision history:
-- 1994-Mar-31    37.0  created
-- 1994-Apr-01    37.1  added FIXHSYNC and SYNCTRUE options  
-- 1994-Apr-02    37.2  added HSYNCDELAY option
-- 1994-Apr-04    37.3  added VSYNCDELAY option
-- 1994-Apr-09    37.4  some minor changes to argument parsing
--                      FIXHSYNC option removed
-- 1994-Apr-21    37.5  HSYNC and VSYNC flags are now reset to zeros if
--                      no ...SYNCTRUE is specified   
-- 1994-Apr-26    37.6  above behaviour changed: sync flags are now left
--                      alone if no ...SYNCTRUE option is specified
-- 1994-May-03    37.7  improved ...SYNCDELAY range checking
-- 1994-May-04    37.8  added ...SYNCLEN and HSYNCFALSE, VSYNCFALSE keywds.
-- 1994-May-05    37.9  lots of bug fixes, range checking modified
--
-------------------------------------------------------------------------*/

#define __USE_SYSBASE

#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <graphics/monitor.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#ifdef GERMAN
#include "german_text.h"
#else
#include "english_text.h"
#endif

extern long __oslibversion = 37;

static char version[] = "$VER: MPatch 37.9 (5.5.94)";

#define NOT_CHANGED  (-1)

UWORD beamconMask = 0xffff, beamconValue = 0x0000;
WORD hsync_delay = NOT_CHANGED, vsync_delay = NOT_CHANGED;
WORD hsync_len = NOT_CHANGED, vsync_len = NOT_CHANGED;

BOOL modifyMonitor(char *name)
{
   struct MonitorSpec *mspec;
   struct SpecialMonitor *sm;
   BOOL result = FALSE;
   UWORD beamcon;
      
   if (mspec=OpenMonitor(name,0L))
   {
      result=TRUE;
/*--- modify beamcon register ---*/
      beamcon=mspec->BeamCon0;
      beamcon &= beamconMask;
      beamcon |= beamconValue;
      Forbid();
      mspec->BeamCon0=beamcon;
      Permit();
/*--- perform hsync modifications ---*/
      if (sm=mspec->ms_Special)
      {
         if (hsync_delay<0)
            hsync_delay = sm->hsync.asi_Start;
         else
            hsync_delay += sm->hblank.asi_Start;
         if (hsync_len<2)
            hsync_len = sm->hsync.asi_Stop - sm->hsync.asi_Start;
         if (hsync_delay + hsync_len <= sm->hblank.asi_Stop)
         {
            Forbid();
            sm->hsync.asi_Start=hsync_delay;
            sm->hsync.asi_Stop=hsync_delay + hsync_len;
            Permit();
         }
/*--- perform vsync modifications ---*/
         if (vsync_delay<0)
            vsync_delay = sm->vsync.asi_Start / mspec->total_colorclocks;
         if (vsync_len<2)
            vsync_len = (sm->vsync.asi_Stop - sm->vsync.asi_Start) / mspec->total_colorclocks;
         if (vsync_delay + vsync_len < mspec->min_row / 2)
         {
            Forbid();
            sm->vsync.asi_Start=vsync_delay * mspec->total_colorclocks;
            sm->vsync.asi_Stop=(vsync_delay + vsync_len) * mspec->total_colorclocks;
            Permit();
         }
      }
      CloseMonitor(mspec);
   }
   return(result);
}

void main(void)
{
   long rc = RETURN_OK;
   struct RDArgs *ra;
   char buffer[32];
   char *bufptr = buffer;
   static char template[] = "MONITOR/A,HSYNCTRUE/S,VSYNCTRUE/S,SYNCTRUE/S,HSYNCFALSE/S,VSYNCFALSE/S,SYNCFALSE/S,LOLDIS/S,HSYNCDELAY/K/N,VSYNCDELAY/K/N,HSYNCLEN/K/N,VSYNCLEN/K/N";
   enum value_ids { MONITOR_NAME=0,HSYNC_TRUE,VSYNC_TRUE,SYNC_TRUE,HSYNC_FALSE,VSYNC_FALSE,SYNC_FALSE,LOLDIS_FLAG,HSYNC_DELAY,VSYNC_DELAY,HSYNC_LEN,VSYNC_LEN,MAX_VALUES };
   LONG values[MAX_VALUES] = {0,0,0,0,0,0,0,0,0,0,0,0};
   
   if (ra=ReadArgs(template,values,NULL))
   {
      if (values[HSYNC_TRUE])
      {
         beamconMask &= ~(HSYNCTRUE | VSYNCTRUE);
         beamconValue |= HSYNCTRUE;
      }
      if (values[HSYNC_FALSE])
      {
         beamconMask &= ~HSYNCTRUE;
         beamconValue &= ~VSYNCTRUE;
      }
      if (values[VSYNC_TRUE])
      {
         beamconMask &= ~(HSYNCTRUE | VSYNCTRUE);
         beamconValue |= VSYNCTRUE;
      }
      if (values[VSYNC_FALSE])
      {
         beamconMask &= ~VSYNCTRUE;
         beamconValue &= ~VSYNCTRUE;
      }
      if (values[SYNC_TRUE])
      {
         beamconMask &= ~(HSYNCTRUE | VSYNCTRUE);
         beamconValue |= (HSYNCTRUE | VSYNCTRUE);
      }
      if (values[SYNC_FALSE])
      {
         beamconMask &= ~(HSYNCTRUE | VSYNCTRUE);
         beamconValue &= ~(HSYNCTRUE | VSYNCTRUE);
      }
      if (values[LOLDIS_FLAG])
         beamconValue |= LOLDIS;
      if (values[HSYNC_DELAY])
         hsync_delay = *(long*)values[HSYNC_DELAY];
      if (values[VSYNC_DELAY])
         vsync_delay = *(long*)values[VSYNC_DELAY];
      if (values[HSYNC_LEN])
         hsync_len = *(long*)values[HSYNC_LEN];
      if (values[VSYNC_LEN])
         vsync_len = *(long*)values[VSYNC_LEN];
      strcpy(buffer,(char*)values[MONITOR_NAME]);
      while ((*bufptr) && (*bufptr!='.')) bufptr++;
      if (*bufptr==0) strcat(buffer,".monitor");
      if (!modifyMonitor(buffer))
      {
         Printf(TXT_NOMONITOR,buffer);
         rc=RETURN_ERROR;
      }
      FreeArgs(ra);
   }
   else
   {
      Printf(TXT_INVALIDARGS,template);
      rc=RETURN_ERROR;
   }
   exit(rc);
}
