# include "dgd.h"
# include <exec/types.h>
# include <exec/libraries.h>
# include <exec/execbase.h>
# include <dos/dos.h>
# include <dos/dosextens.h>
# include <intuition/intuition.h>
# include <workbench/icon.h>
# include <workbench/startup.h>
# include <workbench/workbench.h>

# include <clib/alib_protos.h>
# include <clib/dos_protos.h>
# include <clib/exec_protos.h>
# include <clib/icon_protos.h>

# include <stdlib.h>
# include <stdio.h>
# include <strings.h>
# include <stdarg.h>

# ifndef DGD_PRECOMP
# include "alarm.h"
# endif

struct Library *IconBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
extern struct Library *SysBase; /* DICE runtime will open it */

# include "amiversion.h"

static struct _args_ {
    char *configname;
    char *filename;
# ifndef DGD_PRECOMP
    char *msgname;
    long nomsgs;
# endif
} args = {
    NULL, NULL
# ifndef DGD_PRECOMP
  , NULL, DOSFALSE
# endif
};

static char configName[256];
static char fileName[256];
# ifndef DGD_PRECOMP
static char msgName[256];
# endif
static struct RDArgs *rdargs = NULL;

static FILE *msgfile = NULL;
static APTR oldException = NULL;
static ULONG oldExceptSig = 0L;

/*
 * NAME:        main()
 * DESCRIPTION: main program
 */
int main(argc, argv)
int argc;
char *argv[];
{
    char *vp = ver;  /* so the version string won't be optimized away */
    char *argneu[4];

    if (SysBase->lib_Version < 36) {
        fprintf(stderr, "Fatal: Need OS 2.0 to run.\n");
        exit(20);
    }

# ifndef DGD_PRECOMP
    rdargs = ReadArgs("CONFIG/A,DUMP,MSGFILE,NOMSGS/S", &args, NULL);
# else
    rdargs = ReadArgs("CONFIG/A,FILE/A", &args, NULL);
# endif
    if (!rdargs) {
        PrintFault(IoErr(), argv[0]);
        exit(10);
    }

# ifndef DGD_PRECOMP
    fprintf(stderr, "dgd %s (%s)\n", DGDVERSION, NETVERSION);
# else
    fprintf(stderr, "dgd-precompiler %s\n", DGDVERSION);
# endif

    for (argc = 0; argc < 3; argc++) {
      switch (argc) {
        case 0: argneu[0] = argv[0]; break;
        case 1: argneu[1] = args.configname; break;
        case 2: argneu[2] = args.filename; break;
      }
      if (!argneu[argc])
          break;
    }
    argneu[3] = NULL;

# ifndef DGD_PRECOMP
    if (!args.nomsgs && args.msgname) {
        msgfile = fopen(args.msgname, "w");
        if (!msgfile) {
            fprintf(stderr, "Can't open message file '%s'", args.msgname);
            perror("");
        }
    }
    oldException = ((struct Task*)FindTask(NULL))->tc_ExceptCode;
    oldExceptSig = SetExcept(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C);
    handler_int = finish;
# endif
    P_srandom(P_time());
    return dgd_main(argc, argneu);
}

# ifndef DGD_PRECOMP

/*
 * NAME:        ParseIcon()
 * DESCRIPTION: Parse the arguments of one icon
 */
static void ParseIcon (struct DiskObject *myIcon)
{
  char *type;

  if (myIcon != NULL) {
    type = FindToolType(myIcon->do_ToolTypes,"CONFIG");
    if (type != NULL)
        args.configname = strcpy (configName, type);
    type = FindToolType(myIcon->do_ToolTypes,"DUMP");
    if (type != NULL)
        args.filename = strcpy (fileName, type);
    type = FindToolType(myIcon->do_ToolTypes,"MSGFILE");
    if (type != NULL)
        args.msgname = strcpy (msgName, type);
    type = FindToolType(myIcon->do_ToolTypes,"NOMSGS");
    if (type != NULL)
        args.nomsgs = DOSTRUE;
  }
}

/*
 * NAME:        ParseWBArgs()
 * DESCRIPTION: Parse the icon arguments given to the program
 */
static void ParseWBArgs (struct WBStartup *wbm)
{
  char *type;
  int   argNr;
  struct Process *me;
  struct DiskObject *myIcon;
  BPTR oldCurrentDir;

  args.msgname = strcpy(msgName, "CON:0/11/640/10//dgd " DGDVERSION " " NETVERSION "/AUTO");
  me = (struct Process *)FindTask(NULL);

  if (wbm->sm_NumArgs > 2)
      return;

  argNr = wbm->sm_NumArgs - 1;
  type = wbm->sm_ArgList[argNr].wa_Name;
  oldCurrentDir = me->pr_CurrentDir;
  CurrentDir(wbm->sm_ArgList[argNr].wa_Lock);
  myIcon = GetDiskObject(type);
  CurrentDir(oldCurrentDir);

  ParseIcon(myIcon);
  if (myIcon != NULL)
    FreeDiskObject(myIcon);
}

/*
 * NAME:        host->wbmain()
 * DESCRIPTION: Amiga-specific entrypoint for WB-launched programs.
 */
int wbmain (struct WBStartup *msg)
{
    char *argneu[4];
    int  argc;

    IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 33);
    if (IntuitionBase == NULL)
        exit (20);
    IconBase = (struct Library *) OpenLibrary(ICONNAME, 33);
    if (IconBase == NULL) {
        DisplayBeep(NULL);
        CloseLibrary(IntuitionBase);
        exit(20);
    }

    ParseWBArgs(msg);

    for (argc = 0; argc < 3; argc++) {
      switch (argc) {
        case 0: argneu[0] = msg->sm_ArgList[0].wa_Name; break;
        case 1: argneu[1] = args.configname; break;
        case 2: argneu[2] = args.filename; break;
      }
      if (!argneu[argc])
        break;
    }
    argneu[3] = NULL;

    atexit(P_finish);

# ifndef DGD_PRECOMP
    if (!args.nomsgs && args.msgname) {
        msgfile = fopen(args.msgname, "w");
        if (!msgfile) {
            fprintf(stderr, "Can't open message file '%s'", args.msgname);
            perror("");
        }
    }
    oldException = ((struct Task*)FindTask(NULL))->tc_ExceptCode;
    oldExceptSig = SetExcept(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C);
    handler_int = finish;
# endif
    P_srandom(P_time());
    return dgd_main(argc, argneu);
}

# endif

/*
 * NAME:        P->finish()
 * DESCRIPTION: host specific tidying up
 */
void P_finish()
{
    static short done = 0;

    if (done++) return;  /* May be called multiple times */
# ifndef DGD_PRECOMP
    cleanup_alarm();
    SetExcept (oldExceptSig, sys_signal_alarm|SIGBREAKF_CTRL_C);
    ((struct Task*)FindTask(NULL))->tc_ExceptCode = oldException;
    if (msgfile && msgfile != stderr) {
        fclose(msgfile);
        msgfile = NULL;
    }
# endif
    if (rdargs) {
        FreeArgs(rdargs);
        rdargs = NULL;
    }
    if (IntuitionBase) {
        CloseLibrary(IntuitionBase);
        IntuitionBase = NULL;
    }
    if (IconBase) {
        CloseLibrary(IconBase);
        IconBase = NULL;
    }
}

/*
 * NAME:      P->getevent()
 * DESCRIPTION:       get an event (but there are none)
 */
void P_getevent()
{
}

/*
 * NAME:        P->message()
 * DESCRIPTION: show message
 */
void P_message(mess)
char *mess;
{
    if (msgfile)
      {
        fputs(mess, msgfile);
        fflush(msgfile);
      }
    if (msgfile != stderr)
      {
        fputs(mess, stderr);
        fflush(stderr);
      }
}

/*-----------------------------------------------------------------------
** DICE-specifics.
*/

#if defined(_DCC)

# ifndef DGD_PRECOMP
/*-----------------------------------------------------------------------
** The routine the DICE runtime lib will call for Ctrl-C checks.
** It is overloaded so it will work with DGDs special signal handling.
*/

void chkabort(void) { check_signals(); }
# endif

/*-----------------------------------------------------------------------
** DICE has the prototype, but not the fun...
*/

void *memchr (const void *buf, int c, size_t s) {
  while (s--) if (*(char *)buf == (char) c) return buf; else ((char *)buf)++;
  return NULL;
}

#endif /* DICE */
