
#include <installerngmodule_base.h>

#include <exec/types.h>

#include <clib/savage_protos.h>
#include <clib/debuglib_protos.h>

#include <proto/dos.h>

#include <libraries/installerngmodule.h>

#include <dos/dos.h>
#include <savage/macros.h>

/******************************************************************************/

static int tabs=0;

/******************************************************************************/

static void pp_Print(char *);
static void pp_PrintF(char *, ULONG);
static void pp_PrintTabs(void);

static BOOL pp_PrintTree(struct TreeNode *);
static BOOL pp_PrintTreeList(struct List *);
static BOOL pp_PrintTreeListTail(struct Node *);

static BOOL pp_PrintFunktion(struct TreeNode *);
static BOOL pp_PrintExprlist(struct TreeNode *);
static BOOL pp_PrintProcedure(struct TreeNode *);
static BOOL pp_PrintIdent(char *);
static BOOL pp_PrintString(char *);
static BOOL pp_PrintNumber(long);

/******************************************************************************/

// the entry for this function call
ULONG ingm_PerformAction(register __a0 struct ModuleEnvironment *me)
{
  // print the heade
  pp_Print("\n\n/**\n");
  pp_Print("*** this code was generated by the InstallerNG\n");
  pp_Print("*** 'prettyprinter.module' -- done by savage\n");
  pp_Print("**/\n\n");

  pp_Print("/*************************************************************/\n");
  pp_Print("/* PROCEDURES                                                */\n");
  pp_Print("/*************************************************************/\n\n");
  pp_PrintTreeList(me->me_Procedures);

  pp_Print("\n/*************************************************************/\n");
  pp_Print("/* ONERROR                                                   */\n");
  pp_Print("/*************************************************************/\n\n");
  pp_PrintTreeList(me->me_OnErrors);

  pp_Print("\n/*************************************************************/\n");
  pp_Print("/* EFFECTS                                                   */\n");
  pp_Print("/*************************************************************/\n\n");
  pp_PrintTreeList(me->me_Effects);

  pp_Print("\n/*************************************************************/\n");
  pp_Print("/* THE PROGRAM ITSELF                                        */\n");
  pp_Print("/*************************************************************/\n\n");
  pp_PrintTree(me->me_TreeRoot);

  pp_Print("\n\n\n");

  return 0L;
}

/******************************************************************************/

// print a string
static void pp_Print (char *str)
{
  pp_PrintF(str, NULL);
}

static void pp_PrintF(char *str, ULONG args)
{
  KPrintF(str, args);
}

static void pp_PrintTabs(void)
{
  int i;
  for (i=0; i<tabs; i++) { pp_Print(" "); }
}

/******************************************************************************/

static BOOL pp_PrintTreeList(struct List *list)
{
  return pp_PrintTreeListTail(sav_GetHead(list));
}

/******************************************************************************/

static BOOL pp_PrintTreeListTail(struct Node *node)
{
  BOOL goon = TRUE;

  while (node && goon)
  {
    pp_Print(" ");

    goon = pp_PrintTree((struct TreeNode *) node);
    node = sav_GetSucc(node);
  }

  return goon;
}

/******************************************************************************/

// print the tree; return false, if we want to break the rekursion
static BOOL pp_PrintTree(struct TreeNode *node)
{
  BOOL goon = FALSE;

  // if there is enough free stack space, we go on traversing the tree
  if (sav_StackLeft() < MINIMUM_FREE_STACKSPACE)
  {
    pp_Print("\n\n----> ERROR: NO FREE STACKSPACE LEFT <----\n\n");
  }

  // check for user break
  else if (SIGBREAKF_CTRL_C & CheckSignal(SIGBREAKF_CTRL_C))
  {
    pp_Print("\n\n----> USER BREAK BY CTRL-C <----\n\n");
  }

  // look at the node type and call the print function for one specific node
  else
  {
    switch (node->tn_Type)
    {
      case NODE_FUNCTION:   { goon = pp_PrintFunktion(node); break; }
      case NODE_IDENT:      { goon = pp_PrintIdent(node->tn_Value.tnv_IdentName); break; }
      case NODE_STRING:     { goon = pp_PrintString(node->tn_Value.tnv_String); break; }
      case NODE_NUMBER:     { goon = pp_PrintNumber(node->tn_Value.tnv_Number); break; }

      case NODE_EXPRLIST:   { goon = pp_PrintExprlist(node); break; }
      case NODE_FUNIDENT:   { goon = pp_PrintProcedure(node); break; }
      case NODE_ROOT:       { goon = pp_PrintTreeList(&node->tn_Childs); break; }

      case NODE_FORMATSTR:
      case NODE_FIRSTEXPR:  { goon = TRUE; break; }

      default:              { goon = TRUE; pp_Print("«UNKNOWN-NODE» "); }
    }
  }

  return goon;
}

/******************************************************************************/

// print a function name
static BOOL pp_PrintFunktion(struct TreeNode *node)
{
  BOOL goon = FALSE;

  static unsigned char *funnames[] =
    { "ABORT", "COMPLETE", "COPYFILES", "COPYLIB", "DEBUG", "DELETE",
      "EXECUTE", "EXIT", "FOREACH", "MAKEASSIGN", "MAKEDIR", "MESSAGE",
      "ONERROR", "PROCEDURE", "PROTECT", "RENAME", "REXX", "RUN", "SET",
      "STARTUP", "TEXTFILE", "TOOLTYPE", "TRAP", "USER", "WELCOME",
      "WORKING", "IF", "UNTIL", "WHILE", "EQU", "NE", "GT", "GE", "LT",
      "LE", "+", "-", "*", "/", "AND", "OR", "XOR", "NOT",
      "BITAND", "BITOR", "BITXOR", "BITNOT", "SHIFTLEFT", "SHIFTRIGHT",
      "IN", "ASKDIR", "ASKFILE", "ASKSTRING", "ASKNUMBER", "ASKCHOICE",
      "ASKOPTIONS", "ASKBOOL", "ASKDISK", "CAT", "DATABASE", "EXISTS",
      "EXPANDPATH", "EARLIER", "FILEONLY", "GETASSIGN", "GETDEVICE",
      "GETDISKSPACE", "GETENV", "GETSIZE", "GETSUM", "GETVERSION",
      "PATHONLY", "PATMATCH", "SELECT", "STRLEN", "SUBSTR", "TRANSCRIPT",
      "TACKON", "ALL", "APPEND", "ASSIGNS", "CHOICES", "COMMAND", "CONFIRM",
      "DEFAULT", "DELOPTS", "DEST", "DISK", "FILES", "FONTS", "HELP",
      "INCLUDE", "INFOS", "NEWNAME", "NEWPATH", "NOGAUGE", "NOPOSITION",
      "NOREQ", "OPTIONAL", "PATTERN", "PROMPT", "QUIET", "RANGE",
      "RESIDENT", "SAFE", "SETDEFAULTTOOL", "SETSTACK", "SETTOOLTYPE",
      "SOURCE", "SWAPCOLORS", "SYMBOLSET", "SYMBOLVAL", "ICONINFO",
      "SETPOSITION", "GETTOOLTYPE", "GETDEFAULTTOOL", "GETSTACK",
      "GETPOSITION", "SIMULATE-ERROR", "BEEP", "COMPARE", "FINDBOARD",
      "LET", "REBOOT", "DELAY", "SWING", "RANDOM", "PUT-PROPERTY",
      "GET-PROPERTY", "REMOVE-PROPERTY", "SAFE-PROPERTY-OBJECT",
      "READ-PROPERTY-OBJECT", "CAST-INT", "CAST-STRING", "NOP", "FLUSHLIBS",
      "EFFECT", "SHOWMEDIA", "SETMEDIA", "CLOSEMEDIA", "TRACE", "RETRACE",
      "QUERYDISPLAY","BACK", "OPENWBOBJECT", "SHOWWBOBJECT", "CLOSEWBOBJECT",
      "SETENV" };

  pp_Print("\n");
  pp_PrintTabs();
  pp_Print("(");
  pp_Print(funnames[node->tn_Value.tnv_FunID-1]);

  // dont forget a nodes childes
  if (0 == sav_ListLen((struct List *) &node->tn_Childs)) { }
  else
  {
    tabs += 2;
    goon = pp_PrintTreeList((struct List *) &node->tn_Childs);
    tabs -= 2;
  }

  pp_Print(")");

  return TRUE;
}

/******************************************************************************/

//
static BOOL pp_PrintExprlist(struct TreeNode *node)
{
  BOOL goon;

  pp_Print("\n");
  pp_PrintTabs();
  pp_Print("(");

  tabs += 2;
  goon = pp_PrintTreeList((struct List *) &node->tn_Childs);
  tabs -= 2;

  pp_Print("\n");
  pp_PrintTabs();
  pp_Print(")");

  return goon;
}

/******************************************************************************/

// print an ident name
static BOOL pp_PrintIdent(char *idname)
{
  pp_Print(idname);

  return TRUE;
}

/******************************************************************************/

// print a procedure name
static BOOL pp_PrintProcedure(struct TreeNode *node)
{
  BOOL goon;

  pp_Print("\n");
  pp_PrintTabs();
  pp_Print("(");
  pp_Print(node->tn_Value.tnv_IdentName);

  // dont forget a nodes childes
  if (0 == sav_ListLen((struct List *) &node->tn_Childs)) { }
  else
  {
    tabs += 2;
    goon = pp_PrintTreeList((struct List *) &node->tn_Childs);
    tabs -= 2;
  }

  pp_Print(")\n");

  return goon;
}

/******************************************************************************/

// print a string
static BOOL pp_PrintString(char *str)
{
  unsigned char chrs[] = { 0, 0 };

  pp_Print("\"");

  while (chrs[0] = *str++)
  {
    switch (chrs[0])
    {
      case    0:  { pp_Print("\\0"); break; }
      case    8:  { pp_Print("\\b"); break; }
      case    9:  { pp_Print("\\t"); break; }
      case   10:  { pp_Print("\\n"); break; }
      case   11:  { pp_Print("\\v"); break; }
      case   12:  { pp_Print("\\f"); break; }
      case   13:  { pp_Print("\\r"); break; }
      case  '"':  { pp_Print("\\\""); break; }
      case '\\':  { pp_Print("\\\\"); break; }
      default:    { pp_Print((char *) &chrs); }
    }
  }

  pp_Print("\"");

  return TRUE;
}

/******************************************************************************/

// print a number
static BOOL pp_PrintNumber(long num)
{
  pp_PrintF("%ld", (ULONG) num);

  return TRUE;
}

