/************************************************************************
 *	            FREXX PROGRAMMING LANGUAGE DEBUGGER		        *
 ************************************************************************
 
 FPL debug process main source
 
 ************************************************************************/

/************************************************************************
 *                                                                      *
 * fpl.library - A shared library interpreting script langauge.         *
 * Copyright (C) 1992-1994 FrexxWare                                    *
 * Author: Daniel Stenberg                                              *
 *                                                                      *
 * This program is free software; you may redistribute for non          *
 * commercial purposes only. Commercial programs must have a written    *
 * permission from the author to use FPL. FPL is *NOT* public domain!   *
 * Any provided source code is only for reference and for assurance     *
 * that users should be able to compile FPL on any operating system     *
 * he/she wants to use it in!                                           *
 *                                                                      *
 * You may not change, resource, patch files or in any way reverse      *
 * engineer anything in the FPL package.                                *
 *                                                                      *
 * This program 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.                 *
 *                                                                      *
 * Daniel Stenberg                                                      *
 * Ankdammsgatan 36, 4tr                                                *
 * S-171 43 Solna                                                       *
 * Sweden                                                               *
 *                                                                      *
 * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
 *                                                                      *
 ************************************************************************/

#include <dos/dos.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <exec/ports.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#include "/src/script.h"
#include "debugmail.h"

extern struct ExecBase *SysBase;
struct GfxBase *GfxBase=NULL;
struct IntuitionBase *IntuitionBase=NULL;


#define TEMPLATE "W=Window/k,H=Help/s"
struct args {
  char *window;
  ULONG help;
};

struct Command {
  char *name;
  char flag;
  long ignores;
};

#define COMMAND_IGNORE        1 /* this output is hidden */
#define COMMAND_NOTIGNOREABLE 2 /* this command's output can't be hidden! */

#define STRUCT_ENTRIES(x) sizeof(x)/sizeof(x[0])

struct args argarray;
struct RDArgs *rdargs=NULL;
struct MsgPort *TimerMP=NULL;
struct timerequest *TimerIO=NULL;

BPTR output; /* output file handle for Mprintf() */

void Main(void);
void __regargs Mprintf(char *, ...);

#define DEFAULT_WINDOW "CON:0/0/640/200/FPLdb/AUTO/CLOSE/WAIT/INACTIVE"

#define HELPTEXT "\
Simply run this file to start the FPL debug process!\n\
Default window string is \"%s\"\n"

struct Command cmds[]={
  {"string", 0, 0},
  {"function", 1, 0}, /* default ignore */
  {"start", 0, 0},
  {"exit", 0, 0},
  {"hide", COMMAND_NOTIGNOREABLE, 0},
  {"show", COMMAND_NOTIGNOREABLE, 0},
  {"quit", COMMAND_NOTIGNOREABLE, 0},
  {"lines", 0, 0}
};

#define MAX_NO_FPL 5 /* max number of concurrent debugging libraries */

void *FPL_bases[MAX_NO_FPL]; /* to find them quick! */

long Debugging; /* number of current debugger users */

DebugRet ShowHide(char,    /* TRUE if it is to be hidden */
                  char *); /* function string */

void InputLoop(void);

int main()
{
  output = Output();
  if (SysBase->SoftVer>36) {
    if ((rdargs=ReadArgs(TEMPLATE,(LONG *)&argarray,NULL))) {
      if(argarray.help)
        Mprintf(HELPTEXT, DEFAULT_WINDOW);
      else {
        output = Open(argarray.window?argarray.window:DEFAULT_WINDOW,
                      MODE_NEWFILE);
        if(output) {
          InputLoop();
          Close(output);
        } else {
          output = Output();
          Mprintf("Couldn't open window!\n");
        }
      }
      FreeArgs(rdargs);
    } else
      Mprintf("Bad input!\n");
  } else
    Mprintf("Kickstart must be over 36!\n");
  return 0;
}

void InputLoop()
{
  int count;
  struct MsgPort *port;
  char stop=FALSE;
  int signal;
  char *text;
  struct Messy *mess;

  if (!FindPort(MSGPORT_NAME)) {
    port=CreatePort(MSGPORT_NAME, 0);
    if (port) {
      Mprintf("FPLdb is ready to receive\n");
      while (!stop) {
        signal=Wait((1<<port->mp_SigBit) | SIGBREAKF_CTRL_C);
        if (signal==SIGBREAKF_CTRL_C) {
          stop=TRUE;
        } else {
          mess=(struct Messy *)GetMsg(port);
          if(!(cmds[mess->flag].flag&COMMAND_IGNORE)) {
            struct Data *scr = mess->scr;
            switch(mess->flag) {
            case MAIL_STRING:
              /*
               * Just a plain text string received from another FPLdb process!
               */
              Mprintf("> %s\n", (char *)mess->data);
              break;
            case MAIL_FUNCTION:
              /*
               * Someone invoked a fpl.library function!
               */
              Mprintf("fpl.library/%s(); by %s\n",
                      (char *)mess->data,
                      scr->identifier?scr->identifier:"<unknown>");
              break;
            case MAIL_START:
              /*
               * A process just initialized an FPL debug session!
               */
	      for(count=1; count<MAX_NO_FPL; count++) {
		if(FPL_bases[count]==scr) {
		  count=-1;
		  break;
		}
	      }
	      if(count<0)
	        /* already debugging */
	        break;
	      for(count=1; count<MAX_NO_FPL; count++) {
		if(!FPL_bases[count]) {
		  break;
		}
	      }
	      if(count==MAX_NO_FPL) {
	        /* no room for more! */
		mess->ret = FPLDB_FULL;
		break;
	      }
	      FPL_bases[count] = scr;

	      /*
	       * To find information regarding _this_ process really fast
	       * when called, we store the array position in our field
	       * in the main FPL structure.
	       */
	      scr->debugentry = (void *)count;
	      Debugging++;
              Mprintf("'%s' just initialized a new FPL session\n", (char *)mess->data);
	      break;
            case MAIL_EXIT:
              /*
               * A process just exited an FPL debug session!
               */
	      FPL_bases[(int)scr->debugentry]=NULL;
	      Debugging--;
              Mprintf("'%s' just exited its FPL session\n", (char *)mess->data);
              break;
	      
            case MAIL_HIDE:
              /*
               * A request to prevent a certain debug-output is received!
               */
            case MAIL_SHOW:
              /*
               * A request to show a certain debug-output is received!
               */
              mess->ret = ShowHide(mess->flag==MAIL_HIDE?1:0,
                                   (char *)mess->data);
              Mprintf("* received mail\n");
              break;
            case MAIL_EXITALL:
              /*
               * We should exit!
               */
              stop=TRUE;
              break;
	    case MAIL_EXECUTE:
	      text = scr->text;
	      Mprintf("%ld :", scr->virprg);
	      while(*text && *text!='\n') {
		FPutC(output, *text);
		text++;
	      }
              FPutC(output, '\n');
	      break;
            default:
              Mprintf("Unsupported mail received!\n");
              break;
            }
          } else {
            cmds[mess->flag].ignores++; /* count ignores! */
          }
          ReplyMsg((struct Message *)mess);
        }
      }
      Mprintf("termination signal received!\n");
      Forbid();
      while(mess=(struct Messy *)GetMsg(port))
        ReplyMsg((struct Message *)mess);
      DeletePort(port);
      Permit();
    }
  } else
    Mprintf("FPLdb is already running\n");
}


DebugRet ShowHide(char hide,  /* TRUE if it is to be hidden */
                  char *name) /* function string */
{
  DebugRet ret = FPLDB_OK;
  int count;
  int hit=-1;
  for(count=0; count<STRUCT_ENTRIES(cmds); count++) {
    if(!strcmp(cmds[count].name, name)) {
      hit=count;
      break;
    }
  }
  if(hit>-1) {
    if(cmds[hit].flag&COMMAND_NOTIGNOREABLE)
      ret = FPLDB_CANT_IGNORE;
    else if(hide)
      cmds[hit].flag |= COMMAND_IGNORE;
    else
      cmds[hit].flag &= ~COMMAND_IGNORE;
  } else
    ret = FPLDB_NOTFOUND;
  return ret;
}

void __regargs Mprintf(char *format, ...)
{
  char buffer[256]; /* 256 chars os max length of string to print at once! */
  va_list args;
  va_start(args, format);
  RawDoFmt(format, args, (void (*))"\x16\xc0\x4e\x75", buffer);
  va_end(args);
  Write(output, buffer, strlen(buffer));
}
