/
Crimson2/alias/
Crimson2/area.tmp/
Crimson2/area.tmp/AnomalySpaceDock/
Crimson2/area.tmp/AnomalyStation/
Crimson2/area.tmp/AntHill/
Crimson2/area.tmp/ArcticTerrarium/
Crimson2/area.tmp/BuilderCity/
Crimson2/area.tmp/Dungeon/
Crimson2/area.tmp/MiningDock/
Crimson2/area.tmp/PipeSystem/
Crimson2/area.tmp/RattArea/
Crimson2/area.tmp/RobotFactory/
Crimson2/area.tmp/SilverDale/
Crimson2/area.tmp/StarshipFearless/
Crimson2/area.tmp/StationConduits/
Crimson2/area.tmp/TerrariumAlpha/
Crimson2/area.tmp/TerrariumBeta/
Crimson2/area.tmp/TestArea/
Crimson2/area.tmp/Void/
Crimson2/area/
Crimson2/area/AnomalySpaceDock/
Crimson2/area/AnomalyStation/
Crimson2/area/MiningDock/
Crimson2/area/PipeSystem/
Crimson2/area/SilverDale/
Crimson2/area/StationConduits/
Crimson2/area/Void/
Crimson2/board/
Crimson2/clone/
Crimson2/lib/
Crimson2/mole/
Crimson2/mole/mole_src/HELP/
Crimson2/player/
Crimson2/util/
Crimson2/wldedit/
Crimson2/wldedit/res/
/* decomp.c
 * Written by B. Cameron Lesiuk, 1995
 * Written for use with Crimson2 MUD (written/copyright Ryan Haksi 1995).
 * This source is proprietary. Use of this code without permission from 
 * Ryan Haksi or Cam Lesiuk is strictly prohibited. 
 * 
 * (wi961@freenet.victoria.bc.ca)
 */  

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "crimson2.h"
#include "macro.h"
#include "log.h"
#include "mem.h"
#include "str.h"
#include "ini.h"
#include "send.h"
#include "extra.h"
#include "thing.h"
#include "index.h"
#include "edit.h"
#include "history.h"
#include "socket.h"
#include "code.h"
#include "codestuf.h"
#include "interp.h"
#include "function.h"
#include "compile.h"
#include "decomp.h"

/** Define Statments **/

/* Decompile Options */
#define DMAX_PROG_LENGTH   (1<<13) /* default size of decompile buffer */
#define DMAX_PROG_RECURSE  (1<<7)  /* number of recursions we can handle */

/* formatting options */
#define DINDENT_STR "  "      /* indent string */



/* Structures and unions */

/* Global declarations */
THING *dThing;  /* the thing we send messages to */
BYTE *dComp;    /* pointer to compiled code - to make it global */
WORD dCompOff;  /* where we currently are in dComp buffer */
WORD dCompEnd;  /* offset pointing to next block (ie end of code) */
WORD dCompStart;/* offset pointing to next block (ie end of code) */
WORD dCurSrcMark; /* current source mark number */
WORD *dSrcMark; 
LWORD dSrcMarkSizeByte;
BYTE *dMarkType; /* operand level of mark */
LWORD dMarkTypeSizeByte;
WORD *dStack;    /* position stack */
LWORD dStackSizeByte;
/*WORD *dStackElse;*//* else stack - watch for else's */
/*LWORD dStackElseSizeByte;*/
BYTE *dSrc;     /* pointer to source (decompiled) code */
LWORD dSrcSizeByte; /* size of our decompiled code buffer */
WORD dNumParam; /* our last COP_PUSHV? value, which, coincidentally, 
                   happens to be our # params when immediately preceeding
                   a COP_EXEC or COP_EXECR call. */

WORD dStackPos;                    /* position in stack */

/*WORD dStackElsePos;*/                /* else stack position */

/* This routine is called by the compiler if an error occurs. This routine */
/* should pass the error message etc. on to the appropriate place.         */
void DecompErrorReport(BYTE *dError) {
  SendThing("^w",dThing); /* change color */
  SendThing(dError,dThing);
}

/** Stack Functions **/

WORD DecompInitStack() {
  dStackPos=0;
/*  dStackElsePos=0;*/
  return(0);
}

WORD DecompPush(WORD offset) {
  REALLOC("WARNING! decomp.c stack overflow... resizing\n",
    dStack,WORD,(dStackPos+1),dStackSizeByte);
/*  REALLOC("WARNING! decomp.c else-stack overflow... resizing\n",
    dStackElse,WORD,(dStackPos+1),dStackElseSizeByte);*/
/*  if (dStackPos==DMAX_PROG_RECURSE) {
    DecompErrorReport("decompile error: Stack overflow\n");
    return(DECOMP_INTERNAL_ERROR);
  }*/
  dStack[dStackPos]=offset;
  dStackPos++;
  return(0);
}
WORD DecompPull() {
  if (!dStackPos) {
    DecompErrorReport("decompile error: Stack underflow\n");
    return(DECOMP_INTERNAL_ERROR);
  }
  dStackPos--;
  return(0);
}
WORD DecompTop() {
  if (dStackPos)
    return(dStack[dStackPos-1]);
  else
    return(0);
}

/** Compiled code Functions **/
WORD DecompGetJump() {
  WORD temp;
  temp=(dComp[dCompOff]&0xFF)+((dComp[dCompOff+1]&0xFF)<<8); 
  dCompOff+=2;
  /* the &'s are to guard against sign extension */
  return(temp);
}

/** Decompile code Functions **/
WORD DecompAddByte(BYTE byte) {
  WORD offset;

  offset=dSrcMark[dCurSrcMark];   /* first, find end of chunk */
  while((dSrc[offset])&&(offset<dSrcSizeByte))
    offset++;
  REALLOC("WARNING! decomp.c source buffer overflow... resizing\n",
    dSrc,BYTE,(offset+2),dSrcSizeByte);
/*  if ((offset+1) >=DMAX_PROG_LENGTH) {
    DecompErrorReport("decompile error: source code buffer overflow\n");
    return(DECOMP_INTERNAL_ERROR);
  } */
  dSrc[offset++]=byte;
  dSrc[offset]=0;
  return(0);
}

WORD DecompAddStr(BYTE *str) {
  WORD offset,rc;

  offset=0;
  while(str[offset]) {
    if ((rc=DecompAddByte(str[offset])))
      return(rc);
    offset++;
  }
  return(0);
}

WORD DecompAddChunk(BYTE *str) {
  WORD offset,rc;

  offset=dSrcMark[dCurSrcMark];   /* first, find end of chunk */
  while((dSrc[offset])&&(offset<dSrcSizeByte))
    offset++;
  offset++;
  REALLOC("WARNING! decomp.c source buffer overflow... resizing\n",
    dSrc,BYTE,(offset+strlen(str)+1),dSrcSizeByte);
/*  if ((offset+strlen(str)) >=DMAX_PROG_LENGTH) {
    DecompErrorReport("decompile error: source code buffer overflow\n");
    return(DECOMP_INTERNAL_ERROR);
  }*/
  dCurSrcMark++;
  REALLOC("WARNING! decomp.c Source marker overflow... resizing\n",
    dSrcMark,WORD,(dCurSrcMark+1),dSrcMarkSizeByte);
  REALLOC("WARNING! decomp.c Source marker-type overflow... resizing\n",
    dMarkType,BYTE,(dCurSrcMark+1),dMarkTypeSizeByte);
/*  if (dCurSrcMark >= DMAX_PROG_RECURSE) {
    DecompErrorReport("decompile error: source code recursion overflow\n");
    return(DECOMP_INTERNAL_ERROR);
  }*/
  dSrcMark[dCurSrcMark]=offset;
  dSrc[offset]=0;

  if ((rc=DecompAddStr(str)))
    return(rc);
  return(0);
}

WORD DecompInsertStr(BYTE *str) {
  WORD offset,counter;
  WORD str_len;

  str_len=strlen(str);
  if (!dCurSrcMark) {
    DecompErrorReport("internal error (decomp.c): source marker underflow.\nThis shouldn't happen; it's an error in the program. Contact your Sys Admin.\n");
    return(DECOMP_INTERNAL_ERROR);
  }
  if (!str_len) { /* null string - just clober 0x00 inbetween */
    offset=dSrcMark[dCurSrcMark]-1;
    do {
      dSrc[offset]=dSrc[offset+1];
    }
    while (dSrc[offset++]);
    dCurSrcMark--;
    return(0);
  }
  offset=dSrcMark[dCurSrcMark];
  while((dSrc[offset])&&(offset<dSrcSizeByte))
    offset++;
  offset+=(str_len-1); /* the -1 is because we 'gain' a char from the 0x00 */
  REALLOC("WARNING! decomp.c source buffer overflow... resizing\n",
    dSrc,BYTE,(offset+1),dSrcSizeByte);
/*  if (offset >=DMAX_PROG_LENGTH) {
    DecompErrorReport("decompile error: source code buffer overflow\n");
    return(DECOMP_INTERNAL_ERROR);
  }*/

  while((offset-(str_len-1))>=dSrcMark[dCurSrcMark]) {
    dSrc[offset]=dSrc[offset-(str_len-1)];
    offset--;
  }
  offset=offset-(str_len-1);
  for (counter=0;counter<str_len;counter++) { /* copy string */
    dSrc[offset+counter]=str[counter];
  }
  dCurSrcMark--;
  return(0);
}


WORD DecompSpecialInsertStr(BYTE *str) { /* doesn't take out dSrcMark */
  WORD offset,counter;
  WORD str_len;

  str_len=strlen(str);
  if (!str_len) { /* null string - just exit */
    return(0);
  }
  offset=dSrcMark[dCurSrcMark];
  while((dSrc[offset])&&(offset<dSrcSizeByte))
    offset++;
  offset+=str_len;
  REALLOC("WARNING! decomp.c source buffer overflow... resizing\n",
    dSrc,BYTE,(offset+1),dSrcSizeByte);
/*  if (offset >=DMAX_PROG_LENGTH) {
    DecompErrorReport("decompile error: source code buffer overflow\n");
    return(DECOMP_INTERNAL_ERROR);
  }*/

  offset++;
  while((offset-str_len)>dSrcMark[dCurSrcMark]) {
    offset--;
    dSrc[offset]=dSrc[offset-str_len];
  }

  offset-=str_len;
  for (counter=0;counter<str_len;counter++) { /* copy string */
    dSrc[offset+counter]=str[counter];
  }
  return(0);
}

WORD DecompInsertOp(BYTE *operator,BYTE type) {
  WORD offset,rc;

  offset=0;
  /* NOTE ON BRACKETS */
  /* We only bracket if needed. IE: If the prescidence of the operators
  ** calls for brackets. We also ALWAYS bracket for '=','==','|='. Why?
  ** These operators can also operate on pointer variables and values.
  ** HOWEVER, the result can then be used in INTEGER expressions!!!!!!
  ** To keep the type correct upon decompilation and re-compilation, we
  ** need to put brackets around them. */
  if ((type>dMarkType[dCurSrcMark])||
    (dMarkType[dCurSrcMark]==COP_EQU)||
    (dMarkType[dCurSrcMark]==COP_BEQU)||
    (dMarkType[dCurSrcMark]==COP_BNEQU)) { /* bracket second operand */
    if ((rc=DecompAddByte(')')))
      return(rc);
    if ((rc=DecompSpecialInsertStr("(")))
      return(rc);
  }
  if ((type>dMarkType[dCurSrcMark-1])||
    (dMarkType[dCurSrcMark-1]==COP_EQU)||
    (dMarkType[dCurSrcMark-1]==COP_BEQU)||
    (dMarkType[dCurSrcMark-1]==COP_BNEQU)) { /* bracket first operand */
    offset=dSrcMark[dCurSrcMark];
    while(dSrc[offset++]);
    REALLOC("WARNING! decomp.c source buffer overflow... resizing\n",
      dSrc,BYTE,(offset+5),dSrcSizeByte); /* why +7? just to make sure: " <<= " + 0x00 + extra to be super-paranoid */
/*    if ((offset+2) >=DMAX_PROG_LENGTH) {
      DecompErrorReport("decompile error: source code buffer overflow\n");
      return(DECOMP_INTERNAL_ERROR);
    }*/
    while(offset >= dSrcMark[dCurSrcMark]) {
      dSrc[offset+2]=dSrc[offset];
      offset--;
    }
    dSrc[offset+2]=0;
    dSrc[offset+1]=')';
    offset--;
    while(offset >= dSrcMark[dCurSrcMark-1]) {
      dSrc[offset+1]=dSrc[offset];
      offset--;
    }
    dSrc[offset+1]='('; 
    dSrcMark[dCurSrcMark]+=2; /* we just moved it, remember? */
  }
  if ((rc=DecompInsertStr(operator)))
    return(rc);
  dMarkType[dCurSrcMark]=type;
  return(0);
}


/* Decomp
 * The guts of this whole thing.
 *
 * Decomp is set up similar to Compile:
 * ddComp    = a pointer to the compiled binary code.
 * ddSrc     = a pointer to a pointer to a STR containing the decompiled
 *             (source) code. This STR will be allocated by Decomp.
 * ddThing   = a pointer to a THING to send error messages to. 
 *
 * Returns a return code as defined in decomp.h
 */
WORD Decomp(STR *ddComp,STR **ddSrc,THING *ddThing) { 
  WORD dRc;    /* return code */
  BYTE dTempBuf[100]; /* temporary string buffer */
  BYTE dError[300]; /* error string buffer */
  WORD dFunction;     /* pointer to a function */
  WORD dOffset;     /* pointer to an offset */
  WORD dOffset2;    /* pointer to an offset */
  WORD dOffset3;    /* pointer to an offset */
  WORD dCounter;       /* counter for counting things */
  LWORD dNumber;      /* number extracted from dComp */
  BYTE dInstruction;  /* instruction we're looking at */
  BYTE dLocalVarTable[CMAX_VAR][CVAR_NAME_LENGTH]; /* local variable table */
  WORD dVariable;     /* variable we're reading */
  WORD dIndent; /* current # spaces to indent */
  void *dPtr;   /* void pointer for pointer arguments */

  dThing=ddThing; /* make calling THING globally available */
  dComp=ddComp->sText;
  if ((dRc=DecompInitStack()))
    return(dRc);

  dSrc[0]=0; /* just in case */

  /* The first thing we have to do is check to see if what we've been passed */
  /* is actually compiled code.                                              */
  /* NOTE: the second check (on sLen); it'd be possible to mistake a STR for */
  /*       a program by someone just making a STR->sText=CODE_PROG_HEADER.   */
  /*       However, compiled code always includes, at a minimum, a           */
  /*       terminating segment, thus increasing sLen by a MINIMUM of 1.      */
  /*       Thus, someone could make sText look like code, but sLen will      */
  /*       always tell us a forgery from the real thing.                     */
  if ( (strcmp(dComp,CODE_PROG_HEADER))||
       ( (ddComp->sLen) <= (CODE_PROG_HEADER_LENGTH) )) {
    DecompErrorReport("decompile error: this is not a compiled program!\n");
    return(DECOMP_INPUT_ERROR);
  }

  /* Initialize dLocalVarTable */
  for (dCounter=0;dCounter<cSystemVariable;dCounter++) {
    if (dCounter<cSystemVariableStatic)
      strcpy(dLocalVarTable[dCounter],cSysVar[dCounter].cText);
    else
      strcpy(dLocalVarTable[dCounter],cSysVar[dCounter+1].cText);
  }

  sprintf(dSrc,"{");  /* initial { */
  dCurSrcMark=0;
  dSrcMark[dCurSrcMark]=0;

  /* first, read the variables */
  dCompOff=CODE_PROG_HEADER_LENGTH;
  while((dComp[dCompOff]!=CODE_BLK_VAR_NAME)&&
        (dComp[dCompOff]!=CODE_BLK_NULL)) {
    dCompOff++;
    dCompOff=DecompGetJump();
  }
  if (dComp[dCompOff]==CODE_BLK_VAR_NAME) { /* We have VARS! */
    dCompOff++;
    dCompEnd=DecompGetJump();
    dCompStart=dCompOff;
    dCounter=cSystemVariable+1;
    while(dCompOff<dCompEnd) {
      strcpy(dLocalVarTable[dCounter],&dComp[dCompOff]);
      dCompOff+=(strlen(&dComp[dCompOff])+1);
      dCounter++;
    }
  }

/* next, set up variable declaration region */
  dCompOff=CODE_PROG_HEADER_LENGTH;
  while((dComp[dCompOff]!=CODE_BLK_VAR)&&
        (dComp[dCompOff]!=CODE_BLK_NULL)) {
    dCompOff++;
    dCompOff=DecompGetJump();
  }
  if (dComp[dCompOff]==CODE_BLK_VAR) { /* We have VARS! */
    dCompOff++;
    dCompEnd=DecompGetJump();
    dCompStart=dCompOff;
    dCounter=cSystemVariable+1;
    while(dCompOff<dCompEnd) {
      if ((dCompOff==dCompStart)||(dComp[dCompOff]!=dComp[dCompOff-1])) {
        if (dComp[dCompOff]==CDT_INT) {
          if ((dRc=DecompAddChunk("int ")))  /* These used to say "local int" etc, but local/global/private are not implemented. */
            return(dRc);
        } else if (dComp[dCompOff]==CDT_STR) {
          if ((dRc=DecompAddChunk("str ")))
            return(dRc);
        } else if (dComp[dCompOff]==CDT_THING) {
          if ((dRc=DecompAddChunk("thing ")))
            return(dRc);
        } else if (dComp[dCompOff]==CDT_EXTRA) {
          if ((dRc=DecompAddChunk("extra ")))
            return(dRc);
        } else if (dComp[dCompOff]==CDT_EXIT) {
          if ((dRc=DecompAddChunk("exit ")))
            return(dRc);
        } else {
          if ((dRc=DecompAddChunk("<unrecognized type> ")))
            return(dRc);
        }
      } else {
        if ((dRc=DecompAddStr(", ")))
          return(dRc);
      }
      if ((dRc=DecompAddStr(dLocalVarTable[dCounter])))
        return(dRc);
      dCompOff++;
      dCounter++;
    } /* while */
  }


  /* next, read the program code */
  dCompOff=CODE_PROG_HEADER_LENGTH;
  while((dComp[dCompOff]!=CODE_BLK_CODE)&&
        (dComp[dCompOff]!=CODE_BLK_NULL)) {
    dCompOff++;
    dCompOff=DecompGetJump();
  }
  if (dComp[dCompOff]!=CODE_BLK_NULL) { /* We have CODE! */
    dCompOff++;
    dCompEnd=DecompGetJump();
    dCompStart=dCompOff;
    while(dCompOff<dCompEnd) { /* Great big decompile `while' - the main loop */
      dInstruction=(dComp[dCompOff]&0xff);
      if (BIT(codeSet,CODE_DEBUGDECOMPILE)) {
        sprintf(dError,"\n^G%04X^A: ^a%02X %04X^G",dCompOff,dInstruction,dCurSrcMark);
        SendThing(dError,dThing);
      }
      while(dCompOff==DecompTop()) {
        if ((dRc=DecompAddChunk("}")))
          return(dRc);
        if ((dRc=DecompPull()))
          return(dRc);
      }
      dCompOff++;
      switch(dInstruction) {
        case COP_COMMENT:
          if ((dRc=DecompAddStr("/*")))
            return(dRc);
          if ((dRc=DecompAddStr(&dComp[dCompOff])))
            return(dRc);
          if ((dRc=DecompAddStr("*/")))
            return(dRc);
          dCompOff+=strlen(&dComp[dCompOff])+1;
          break;
        case COP_EQUSR:
          if ((dRc=DecompInsertOp(">>=",COP_EQUSR)))
            return(dRc);
          break;
        case COP_EQUSL:
          if ((dRc=DecompInsertOp("<<=",COP_EQUSL)))
            return(dRc);
          break;
        case COP_EQUOR:
          if ((dRc=DecompInsertOp("|=",COP_EQUOR)))
            return(dRc);
          break;
        case COP_EQUXOR:
          if ((dRc=DecompInsertOp("\\=",COP_EQUXOR)))
            return(dRc);
          break;
        case COP_EQUAND:
          if ((dRc=DecompInsertOp("&=",COP_EQUAND)))
            return(dRc);
          break;
        case COP_EQUSUB:
          if ((dRc=DecompInsertOp("-=",COP_EQUSUB)))
            return(dRc);
          break;
        case COP_EQUADD:
          if ((dRc=DecompInsertOp("+=",COP_EQUADD)))
            return(dRc);
          break;
        case COP_EQUMOD:
          if ((dRc=DecompInsertOp("%=",COP_EQUMOD)))
            return(dRc);
          break;
        case COP_EQUDIV:
          if ((dRc=DecompInsertOp("/=",COP_EQUDIV)))
            return(dRc);
          break;
        case COP_EQUMULT:
          if ((dRc=DecompInsertOp("*=",COP_EQUMULT)))
            return(dRc);
          break;
        case COP_EQU:
          if ((dRc=DecompInsertOp("=",COP_EQU)))
            return(dRc);
          break;
        case COP_BOR:
          if ((dRc=DecompInsertOp("||",COP_BOR)))
            return(dRc);
          break;
        case COP_BAND:
          if ((dRc=DecompInsertOp("&&",COP_BAND)))
            return(dRc);
          break;
        case COP_OR:
          if ((dRc=DecompInsertOp("|",COP_OR)))
            return(dRc);
          break;
        case COP_XOR:
          if ((dRc=DecompInsertOp("\\",COP_XOR)))
            return(dRc);
          break;
        case COP_AND:
          if ((dRc=DecompInsertOp("&",COP_AND)))
            return(dRc);
          break;
        case COP_BEQU:
          if ((dRc=DecompInsertOp("==",COP_BEQU)))
            return(dRc);
          break;
        case COP_BNEQU:
          if ((dRc=DecompInsertOp("!=",COP_BNEQU)))
            return(dRc);
          break;
        case COP_GEQ:
          if ((dRc=DecompInsertOp(">=",COP_GEQ)))
            return(dRc);
          break;
        case COP_GR:
          if ((dRc=DecompInsertOp(">",COP_GR)))
            return(dRc);
          break;
        case COP_LEQ:
          if ((dRc=DecompInsertOp("<=",COP_LEQ)))
            return(dRc);
          break;
        case COP_LS:
          if ((dRc=DecompInsertOp("<",COP_LS)))
            return(dRc);
          break;
        case COP_SR:
          if ((dRc=DecompInsertOp(">>",COP_SR)))
            return(dRc);
          break;
        case COP_SL:
          if ((dRc=DecompInsertOp("<<",COP_SL)))
            return(dRc);
          break;
        case COP_SUB:
          if ((dRc=DecompInsertOp("-",COP_SUB))) 
            return(dRc);
          break;
        case COP_ADD:
          if ((dRc=DecompInsertOp("+",COP_ADD)))
            return(dRc);
          break;
        case COP_MOD:
          if ((dRc=DecompInsertOp("%",COP_MOD)))
            return(dRc);
          break;
        case COP_DIV:
          if ((dRc=DecompInsertOp("/",COP_DIV)))
            return(dRc);
          break;
        case COP_MULT:
          if ((dRc=DecompInsertOp("*",COP_MULT)))
            return(dRc);
          break;
        case COP_POP:
          break;
        case COP_EXEC:
        case COP_EXECR:
          dCurSrcMark--; /* whip out from src our # params value */
          dFunction=DecompGetJump();
          dCounter=0;
          if (dNumParam) {
            dNumParam--;
            while(dNumParam) {
              if ((dRc=DecompInsertStr(",")))
                return(dRc);
              dCounter++;
              dNumParam--;
            }
            if ((dRc=DecompAddByte(')')))
              return(dRc);
          } else {
            if ((dRc=DecompAddChunk(")")))
              return(dRc);
          }
          sprintf(dTempBuf,"%s(",fTable[dFunction].fText);
          if ((dRc=DecompSpecialInsertStr(dTempBuf)))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_TOP_OP;
          break;
        case COP_NOP:
          break;
        case COP_NULL:
          DecompErrorReport("decompile error: invalid NULL op-code encountered.\nThis shouldn't happen. Notify your Sys Admin of this error.\n" );
          return(DECOMP_INPUT_ERROR);
          break;
        case COP_PUSHV1:
          dNumber=dComp[dCompOff++]; /* sign extends */
          dNumParam=dNumber;
          sprintf(dTempBuf,"%li",dNumber);
          if ((dRc=DecompAddChunk(dTempBuf)))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_TOP_OP;
          break;
        case COP_PUSHV2:
          dNumber=(dComp[dCompOff]&0x00FF)+((dComp[dCompOff+1])<<8);
          dNumParam=dNumber;
          dCompOff+=2;
          sprintf(dTempBuf,"%li",dNumber);
          if ((dRc=DecompAddChunk(dTempBuf)))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_TOP_OP;
          break;
        case COP_PUSHV:
        case COP_PUSHV4:
          dNumber=(dComp[dCompOff]&0x000000ff)+
                  ((dComp[dCompOff+1]&0x000000ff)<<8)+
                  ((dComp[dCompOff+2]&0x000000ff)<<16)+
                  ((dComp[dCompOff+3])<<24); /* last one sign-extends */
          dNumParam=dNumber;
          dCompOff+=4;
          sprintf(dTempBuf,"%li",dNumber);
          if ((dRc=DecompAddChunk(dTempBuf)))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_TOP_OP;
          break;
        /* for the -- and ++ operators, the spaces are important. You see, if */
        /* someone enters a=b++ + ++c; which is completely valid, and we then */
        /* go and decompile it to a=b+++++c; the next time it's compiled, it  */
        /* will be interpreted as a=(b++)++ + c; which is NOT valid and NOT   */
        /* what they originally had! Don't worry, I think this problem is only*/
        /* with ++ and -- operators. If we implemented * and &, there may be  */
        /* a problem with them as well, but they aren't implemented, so yahoo!*/
        /* Oh, now that I think about it, we may have a problem with the      */
        /* unary pre-op `-'. I'll go fix that too.                            */
        case COP_BSUB:
          if ((dRc=DecompSpecialInsertStr(" --")))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_BSUB;
          break;
        case COP_BADD:
          if ((dRc=DecompSpecialInsertStr(" ++")))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_BADD;
          break;
        case COP_ASUB:
          if ((dRc=DecompAddStr("-- ")))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_ASUB;
          break;
        case COP_AADD:
          if ((dRc=DecompAddStr("++ ")))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_AADD;
          break;
        case COP_COMP:
          if (COP_COMP>dMarkType[dCurSrcMark]) { /* bracket second operand */
            if ((dRc=DecompAddByte(')')))
              return(dRc);
            if ((dRc=DecompSpecialInsertStr("(")))
              return(dRc);
          }
          if ((dRc=DecompSpecialInsertStr("`")))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_COMP;
          break;
        case COP_NOT:
          if (COP_NOT>dMarkType[dCurSrcMark]) { /* bracket second operand */
            if ((dRc=DecompAddByte(')')))
              return(dRc);
            if ((dRc=DecompSpecialInsertStr("(")))
              return(dRc);
          }
          if ((dRc=DecompSpecialInsertStr("!")))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_NOT;
          break;
        case COP_NEG:
          if (COP_NEG>dMarkType[dCurSrcMark]) { /* bracket second operand */
            if ((dRc=DecompAddByte(')')))
              return(dRc);
            if ((dRc=DecompSpecialInsertStr("(")))
              return(dRc);
          }
          if ((dRc=DecompSpecialInsertStr(" -")))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_NEG;
          break;
        case COP_TERM:
          if ((dRc=DecompAddChunk("stop")))
            return(dRc);
          break;
        case COP_PUSHL:
          dVariable=(dComp[dCompOff]&0x00FF)+((dComp[dCompOff+1]&0xFF)<<8);
          dCompOff+=2;
          if ((dRc=DecompAddChunk(dLocalVarTable[dVariable])))
            return(dRc);
          dMarkType[dCurSrcMark]=COP_TOP_OP;
          break;
        case COP_GOTO:
          dOffset=DecompGetJump();
          if ((dOffset>dCompOff)&&(dCompOff==DecompTop())) {/* else condition */
            if ((dRc=DecompAddChunk("}")))
              return(dRc);
            if ((dRc=DecompAddChunk("else")))
              return(dRc);
            if ((dRc=DecompAddChunk("{")))
              return(dRc);
            if ((dRc=DecompPull()))
              return(dRc);
            if ((dRc=DecompPush(dOffset)))
              return(dRc);
          }
          break;
        case COP_IFZ:
          dOffset=DecompGetJump();
          if ((dRc=DecompPush(dOffset)))
            return(dRc);
          if ((dRc=DecompAddByte(')')))
            return(dRc);
          if ((dRc=DecompSpecialInsertStr("(")))
            return(dRc);
          if ((dRc=DecompSpecialInsertStr("if")))
            return(dRc);
          if ((dRc=DecompAddChunk("{")))
            return(dRc);
          break;
        case COP_WHILEZ:
          dOffset=DecompGetJump();
          if ((dRc=DecompPush(dOffset)))
            return(dRc);
          if ((dRc=DecompAddByte(')')))
            return(dRc);
          if ((dRc=DecompSpecialInsertStr("(")))
            return(dRc);
          if ((dRc=DecompSpecialInsertStr("while")))
            return(dRc);
          if ((dRc=DecompAddChunk("{")))
            return(dRc);
          break;
        case COP_PUSHPT:
          /* Solaris doesn't like this */ 
          /* dPtr=*((void**)(&dComp[dCompOff])); */
          {
            unsigned long i;
            dPtr=NULL;
            for (i=0;i<CODE_PT_SIZE;i++)
              (unsigned long)(dPtr)|=
                ((unsigned long)(dComp[dCompOff+i]))<<(8*i);
          }
          dCompOff+=CODE_PT_SIZE;
          if ((dRc=DecompAddChunk("\"")))
            return(dRc);
          for (dCounter=0;((STR*)dPtr)->sText[dCounter];dCounter++) {
            if ((((STR*)dPtr)->sText[dCounter]=='\"') ||
                (((STR*)dPtr)->sText[dCounter]=='\'') ||
                (((STR*)dPtr)->sText[dCounter]=='\\') ||
                (((STR*)dPtr)->sText[dCounter]=='\?')) {
              if ((dRc=DecompAddByte('\\')))
                return(dRc);
              if ((dRc=DecompAddByte(((STR*)dPtr)->sText[dCounter])))
                return(dRc);
            } else if (((STR*)dPtr)->sText[dCounter]=='\a') {
              if ((dRc=DecompAddStr("\\a")))
                return(dRc);
            } else if (((STR*)dPtr)->sText[dCounter]=='\b') {
              if ((dRc=DecompAddStr("\\b")))
                return(dRc);
            } else if (((STR*)dPtr)->sText[dCounter]=='\f') {
              if ((dRc=DecompAddStr("\\f")))
                return(dRc);
            } else if (((STR*)dPtr)->sText[dCounter]=='\n') {
              if ((dRc=DecompAddStr("\\n")))
                return(dRc);
            } else if (((STR*)dPtr)->sText[dCounter]=='\r') {
              if ((dRc=DecompAddStr("\\r")))
                return(dRc);
            } else if (((STR*)dPtr)->sText[dCounter]=='\t') {
              if ((dRc=DecompAddStr("\\t")))
                return(dRc);
            } else if (((STR*)dPtr)->sText[dCounter]=='\v') {
              if ((dRc=DecompAddStr("\\v")))
                return(dRc);
            } else {
              if ((dRc=DecompAddByte(((STR*)dPtr)->sText[dCounter])))
                return(dRc);
            }
          } /* for loop */
          if ((dRc=DecompAddByte('\"')))
            return(dRc);
          /* free this string */
          /*STRFREE(dPtr);*/
          dMarkType[dCurSrcMark]=COP_TOP_OP;
          break;
        case COP_PUSHG:
        case COP_PUSHP:
        default:
          sprintf(dError,"decompile error: unrecognized op-code: %02X\nThis shouldn't happen. Notify your Sys Admin of this error.\n" 
            ,dComp[dCompOff]);
          DecompErrorReport(dError);
          return(DECOMP_INPUT_ERROR);
          break;
      } /* co-code switch */
      if (BIT(codeSet,CODE_DEBUGDECOMPILE)) {
        if (dInstruction==COP_POP)
          sprintf(dError," ^a%04X^b : ^y;",dCurSrcMark);
        else
          sprintf(dError," ^a%04X^b : ^y%s",dCurSrcMark,&dSrc[dSrcMark[dCurSrcMark]]);
        SendThing(dError,dThing);
      }
    } /* great decompile while */
  } /* if (we found code) */

  /* Lastly, throw on the brackets, et nous sommes finir (c- in French 12) */

  while(dCompOff==DecompTop()) {  /* wrap up any outstanding {'s */
    if ((dRc=DecompAddChunk("}")))
      return(dRc);
    if ((dRc=DecompPull()))
      return(dRc);
  }

  if (DecompTop()) {
    DecompErrorReport("decompile error: Stack non-zero after decompile.\n");
    return(DECOMP_INTERNAL_ERROR);
  }

  if ((dRc=DecompAddChunk("}"))) /* Add final } */
    return(dRc);

  /* now go through the whole thing putting ;s where appropriate */
  dOffset=dSrcMark[dCurSrcMark];   /* first, find end of the last chunk */
  while((dSrc[dOffset])&&(dOffset<dSrcSizeByte))
    dOffset++;
  dCounter=0; /* last `thing' designator */
  for(dOffset2=0;dOffset2<dOffset;dOffset2++) {
    if (dSrc[dOffset2]=='{') {
      while(dSrc[dOffset2])
        dOffset2++;
      dSrc[dOffset2]='\n';
    } else if (dSrc[dOffset2]=='}') {
      while(dSrc[dOffset2])
        dOffset2++;
      dSrc[dOffset2]='\n';
    } else if ((dSrc[dOffset2]=='i')&&(dSrc[dOffset2+1]=='f')&&
               (dSrc[dOffset2+2]=='(')) {
      while(dSrc[dOffset2])
        dOffset2++;
      dSrc[dOffset2]=' ';
    } else if ((dSrc[dOffset2]=='e')&&(dSrc[dOffset2+1]=='l')&&
               (dSrc[dOffset2+2]=='s')&&(dSrc[dOffset2+3]=='e')&&
               (dSrc[dOffset2+4]==0)) {
      while(dSrc[dOffset2])
        dOffset2++;
      dSrc[dOffset2]=' ';
    } else if ((dSrc[dOffset2]=='w')&&(dSrc[dOffset2+1]=='h')&&
               (dSrc[dOffset2+2]=='i')&&(dSrc[dOffset2+3]=='l')&&
               (dSrc[dOffset2+4]=='e')&&(dSrc[dOffset2+5]=='(')) {
      while(dSrc[dOffset2])
        dOffset2++;
      dSrc[dOffset2]=' ';
    } else {
      while(dSrc[dOffset2])
        dOffset2++;
      dSrc[dOffset2]=';';
    }
  }
  dSrc[dOffset]=0;
  /* and now, since we have one great big string, let's indent */
  dIndent=0;
  for (dOffset2=0;dOffset2<dOffset;dOffset2++) {
    if (dSrc[dOffset2]=='\"') { /* quote - don't process */
      do {
        if (dSrc[dOffset2]=='\\') dOffset2++;
        dOffset2++;
      } while(dSrc[dOffset2]!='\"');
    } else if (dSrc[dOffset2]==';') { /* cr + indent */
      dOffset2++;
      if (dSrc[dOffset2]=='}')
        dIndent--;
      dTempBuf[0]='\n';
      dTempBuf[1]=0;
      for(dCounter=0;dCounter<dIndent;dCounter++)
        strcat(dTempBuf,DINDENT_STR);
      dCounter=strlen(dTempBuf);
      REALLOC("WARNING! decomp.c source buffer overflow... resizing\n",
        dSrc,BYTE,(dOffset+dCounter+1),dSrcSizeByte);
      for(dOffset3=dOffset;dOffset3>=dOffset2;dOffset3--) 
        dSrc[dOffset3+dCounter]=dSrc[dOffset3];
      for(dOffset3=0;dOffset3<dCounter;dOffset3++)
        dSrc[dOffset2+dOffset3]=dTempBuf[dOffset3];
      dOffset+=dCounter;
    } else if (dSrc[dOffset2]=='\n') {
      dOffset2++;
      if (dSrc[dOffset2]=='}')
        dIndent--;
      dTempBuf[0]=0;
      for(dCounter=0;dCounter<dIndent;dCounter++)
        strcat(dTempBuf,DINDENT_STR);
      dCounter=strlen(dTempBuf);
      REALLOC("WARNING! decomp.c source buffer overflow... resizing\n",
        dSrc,BYTE,(dOffset+dCounter+1),dSrcSizeByte);
      for(dOffset3=dOffset;dOffset3>=dOffset2;dOffset3--) 
        dSrc[dOffset3+dCounter]=dSrc[dOffset3];
      for(dOffset3=0;dOffset3<dCounter;dOffset3++)
        dSrc[dOffset2+dOffset3]=dTempBuf[dOffset3];
      dOffset+=dCounter;
    } else if (dSrc[dOffset2]=='{') {
      dIndent++;
    }
  }
  *ddSrc=STRCREATE(dSrc);
  return(DECOMP_OK);
}


WORD DecompDisassemble(STR *ddComp,THING *ddThing) { 
  BYTE dBuf[300]; /* error string buffer */
  WORD dFunction;     /* pointer to a function */
  WORD dCounter;       /* counter for counting things */
  LWORD dNumber;      /* number extracted from dComp */
  BYTE dInstruction;  /* instruction we're looking at */
  WORD dVariable;     /* pointer to a variable */
  BYTE dLocalVarTable[CMAX_VAR][CVAR_NAME_LENGTH]; /* local variable table */
  void *dPtr;         /* general pointer - to STR or something */

  dThing=ddThing; /* make calling THING globally available */
  dComp=ddComp->sText;

  /* The first thing we have to do is check to see if what we've been passed */
  /* is actually compiled code.                                              */
  /* NOTE: the second check (on sLen); it'd be possible to mistake a STR for */
  /*       a program by someone just making a STR->sText=CODE_PROG_HEADER.   */
  /*       However, compiled code always includes, at a minimum, a           */
  /*       terminating segment, thus increasing sLen by a MINIMUM of 1.      */
  /*       Thus, someone could make sText look like code, but sLen will      */
  /*       always tell us a forgery from the real thing.                     */
  if ( (strcmp(dComp,CODE_PROG_HEADER))||
       ( (ddComp->sLen) <= (CODE_PROG_HEADER_LENGTH) )) {
    DecompErrorReport("disassemble error: this is not a compiled program!\n");
    return(DECOMP_INPUT_ERROR);
  }

  /* Initialize dLocalVarTable */
  for (dCounter=0;dCounter<cSystemVariable;dCounter++) {
    if (dCounter<cSystemVariableStatic)
      strcpy(dLocalVarTable[dCounter],cSysVar[dCounter].cText);
    else
      strcpy(dLocalVarTable[dCounter],cSysVar[dCounter+1].cText);
  }

  /* first, read the variables */
  dCompOff=CODE_PROG_HEADER_LENGTH;
  while((dComp[dCompOff]!=CODE_BLK_VAR_NAME)&&
        (dComp[dCompOff]!=CODE_BLK_NULL)) {
    dCompOff++;
    dCompOff=DecompGetJump();
  }
  if (dComp[dCompOff]==CODE_BLK_VAR_NAME) { /* We have VARS! */
    dCompOff++;
    dCompEnd=DecompGetJump();
    dCompStart=dCompOff;
    dCounter=cSystemVariable+1;
    while(dCompOff<dCompEnd) {
      strcpy(dLocalVarTable[dCounter],&dComp[dCompOff]);
      dCompOff+=(strlen(&dComp[dCompOff])+1);
      dCounter++;
    }
  }

  /* next, read the program code */
  dCompOff=CODE_PROG_HEADER_LENGTH;
  while((dComp[dCompOff]!=CODE_BLK_CODE)&&
        (dComp[dCompOff]!=CODE_BLK_NULL)) {
    dCompOff++;
    dCompOff=DecompGetJump();
  }
  if (dComp[dCompOff]!=CODE_BLK_NULL) { /* We have CODE! */
    dCompOff++;
    dCompEnd=DecompGetJump();
    dCompStart=dCompOff;
sprintf(dBuf,"Disassemble: start=%04X, end=%04X\n",dCompStart,dCompEnd);
SendThing(dBuf,dThing);
    while(dCompOff<dCompEnd) { /* Great disassemble `while' */
      dInstruction=(dComp[dCompOff]&0xff);
      sprintf(dBuf,"^G%04X^A:  ^a%02X",dCompOff,dInstruction);
      SendThing(dBuf,dThing);
      dCompOff++;
      switch(dInstruction) {
        case COP_COMMENT:
          sprintf(dBuf," <text>      ^C/*%s*/\n",&dComp[dCompOff]);
          SendThing(dBuf,dThing);
          dCompOff+=strlen(&dComp[dCompOff])+1;
          break;
        case COP_EQUSR:
          SendThing("             ^C>>=\n",dThing);
          break;
        case COP_EQUSL:
          SendThing("             ^C<<=\n",dThing);
          break;
        case COP_EQUOR:
          SendThing("             ^C|=\n",dThing);
          break;
        case COP_EQUXOR:
          SendThing("             ^C\\=\n",dThing);
          break;
        case COP_EQUAND:
          SendThing("             ^C&=\n",dThing);
          break;
        case COP_EQUSUB:
          SendThing("             ^C-=\n",dThing);
          break;
        case COP_EQUADD:
          SendThing("             ^C+=\n",dThing);
          break;
        case COP_EQUMOD:
          SendThing("             ^C%=\n",dThing);
          break;
        case COP_EQUDIV:
          SendThing("             ^C/=\n",dThing);
          break;
        case COP_EQUMULT:
          SendThing("             ^C*=\n",dThing);
          break;
        case COP_EQU:
          SendThing("             ^C=\n",dThing);
          break;
        case COP_BOR:
          SendThing("             ^C||\n",dThing);
          break;
        case COP_BAND:
          SendThing("             ^C&&\n",dThing);
          break;
        case COP_OR:
          SendThing("             ^C|\n",dThing);
          break;
        case COP_XOR:
          SendThing("             ^C\\\n",dThing);
          break;
        case COP_AND:
          SendThing("             ^C&\n",dThing);
          break;
        case COP_BEQU:
          SendThing("             ^C==\n",dThing);
          break;
        case COP_BNEQU:
          SendThing("             ^C!=\n",dThing);
          break;
        case COP_GEQ:
          SendThing("             ^C>=\n",dThing);
          break;
        case COP_GR:
          SendThing("             ^C>\n",dThing);
          break;
        case COP_LEQ:
          SendThing("             ^C<=\n",dThing);
          break;
        case COP_LS:
          SendThing("             ^C<\n",dThing);
          break;
        case COP_SR:
          SendThing("             ^C>>\n",dThing);
          break;
        case COP_SL:
          SendThing("             ^C<<\n",dThing);
          break;
        case COP_SUB:
          SendThing("             ^C-\n",dThing);
          break;
        case COP_ADD:
          SendThing("             ^C+\n",dThing);
          break;
        case COP_MOD:
          SendThing("             ^C%\n",dThing);
          break;
        case COP_DIV:
          SendThing("             ^C/\n",dThing);
          break;
        case COP_MULT:
          SendThing("             ^C*\n",dThing);
          break;
        case COP_POP:
          SendThing("             ^Cpop\n",dThing);
          break;
        case COP_NOP:
          SendThing("             ^Cnop\n",dThing);
          break;
        case COP_EXEC:
        case COP_EXECR: 
          dFunction=DecompGetJump();
          if (dInstruction==COP_EXEC) {
            sprintf(dBuf," ^a%02X %02X       ^Cexec   %s(",
              (dFunction&0xFF),((dFunction&0xFF00)>>8),
              fTable[dFunction].fText);
          } else {
            sprintf(dBuf," ^a%02X %02X       ^Cexecr  %s(",
              (dFunction&0xFF),((dFunction&0xFF00)>>8),
              fTable[dFunction].fText);
          }
          SendThing(dBuf,dThing);
          dCounter=0;
          while(fTable[dFunction].fParamType[dCounter]!=CDT_NULL) {
            if (dCounter) 
              SendThing("^C,",dThing);
            switch(fTable[dFunction].fParamType[dCounter]) {
              case CDT_INT:
                SendThing("^Rint",dThing);
                break;
              case CDT_STR:
                SendThing("^Rstr",dThing);
                break;
              case CDT_THING:
                SendThing("^Rthing",dThing);
                break;
              case CDT_EXTRA:
                SendThing("^Rextra",dThing);
                break;
              case CDT_EXIT:
                SendThing("^Rexit",dThing);
                break;
              case CDT_ETC:
                SendThing("^Retc...",dThing);
                break;
              default:
                SendThing("^R???",dThing);
                break;
            }
            dCounter++;
          }
          SendThing("^C)\n",dThing);
          break;
  case COP_NULL:
          SendThing("             ^Cnull ^r<this should ^ynot^r happen>\n",dThing);
          break;
        case COP_PUSHV1:
          dNumber=dComp[dCompOff++]; /* sign extends */
          sprintf(dBuf," ^a%02lX          ^Cpushv1 %li\n",(dNumber&0xFF),dNumber);
          SendThing(dBuf,dThing);
          break;
        case COP_PUSHV2:
          dNumber=(dComp[dCompOff]&0xFF)+((dComp[dCompOff+1]&0xFF)<<8);
          sprintf(dBuf," ^a%02X %02X       ^Cpushv2 %li\n",
                 (dComp[dCompOff]&0xFF),(dComp[dCompOff+1]&0xFF),dNumber);
          SendThing(dBuf,dThing);
          dCompOff+=2;
          break;
        case COP_PUSHV:
        case COP_PUSHV4:
          dNumber=(dComp[dCompOff]&0xff)+
                  ((dComp[dCompOff+1]&0xff)<<8)+
                  ((dComp[dCompOff+2]&0xff)<<16)+
                  ((dComp[dCompOff+3]&0xff)<<24);
          if (dInstruction==COP_PUSHV) {
            sprintf(dBuf," ^a%02X %02X %02X %02X ^Cpushv  %li\n",
              (dComp[dCompOff]&0xFF),(dComp[dCompOff+1]&0xFF),
              (dComp[dCompOff+2]&0xFF),(dComp[dCompOff+3]&0xFF),dNumber);
          } else {
            sprintf(dBuf," ^a%02X %02X %02X %02X ^Cpushv4 %li\n",
              (dComp[dCompOff]&0xFF),(dComp[dCompOff+1]&0xFF),
              (dComp[dCompOff+2]&0xFF),(dComp[dCompOff+3]&0xFF),dNumber);
          }
          SendThing(dBuf,dThing);
          dCompOff+=4;
          break;
        case COP_BSUB:
          SendThing("             ^CB--\n",dThing);
          break;
        case COP_BADD:
          SendThing("             ^CB++\n",dThing);
          break;
        case COP_ASUB:
          SendThing("             ^CA--\n",dThing);
          break;
        case COP_AADD:
          SendThing("             ^CA++\n",dThing);
          break;
        case COP_COMP:
          SendThing("             ^C`\n",dThing);
          break;
        case COP_NEG:
          SendThing("             ^C- (neg)\n",dThing);
          break;
        case COP_NOT:
          SendThing("             ^C!\n",dThing);
          break;
        case COP_TERM:
          SendThing("             ^Cstop\n",dThing);
          break;
        case COP_GOTO:
          dFunction=DecompGetJump();
          sprintf(dBuf," ^a%02X %02X       ^Cgoto   ^G%04X\n",
              (dFunction&0xFF),((dFunction&0xFF00)>>8),(dFunction&0xFFFF));
          SendThing(dBuf,dThing);
          break;
        case COP_IFZ:
          dFunction=DecompGetJump();
          sprintf(dBuf," ^a%02X %02X       ^Cifz    ^G%04X\n",
              (dFunction&0xFF),((dFunction&0xFF00)>>8),(dFunction&0xFFFF));
          SendThing(dBuf,dThing);
          break;
        case COP_WHILEZ:
          dFunction=DecompGetJump();
          sprintf(dBuf," ^a%02X %02X       ^Cwhilez ^G%04X\n",
              (dFunction&0xFF),((dFunction&0xFF00)>>8),(dFunction&0xFFFF));
          SendThing(dBuf,dThing);
          break;
        case COP_PUSHL:
          dVariable=DecompGetJump();
          sprintf(dBuf," ^a%02X %02X       ^Cpushl  ^R%s\n",
              (dVariable&0xFF),((dVariable&0xFF00)>>8),dLocalVarTable[dVariable]);
          SendThing(dBuf,dThing);
          break;
        case COP_PUSHPT:
          /* Solaris doesn't like this */ 
          /* dPtr=*((void**)(&dComp[dCompOff])); */
          {
            unsigned long i;
            dPtr=NULL;
            for (i=0;i<CODE_PT_SIZE;i++)
              (unsigned long)(dPtr)|=
                ((unsigned long)(dComp[dCompOff+i]))<<(8*i);
          }
          dCompOff+=CODE_PT_SIZE;
          /*
          for (dCounter=0;dCounter<CODE_PT_SIZE;dCounter++) {
            dPtr|=(dComp[dCompOff]&0xFF)<<(8*dCounter);
            dCompOff++;
          }
          */
          sprintf(dBuf,"^a%8p     ^Cpushpt ^R\"%s\"\n",dPtr,((STR *)dPtr)->sText);
          SendThing(dBuf,dThing);
          break;
        case COP_PUSHG:
        case COP_PUSHP:
        default:
          SendThing("             ^C<unknown> ^r<this should ^ynot^r happen>\n",dThing);
          break;
      } /* co-code switch */
    } /* great disassemble while */
  } /* if (we found code) */

  return(DECOMP_OK);
}

/* DecompInit()
 * Initializes structures required by Decomp.c
 */
void DecompInit() {
  /* allocate our decompile buffer */
  dSrcSizeByte=DMAX_PROG_LENGTH*sizeof(BYTE);
  MALLOC((void *)dSrc,BYTE,dSrcSizeByte);

  /* allocate our markers */
  dSrcMarkSizeByte=DMAX_PROG_RECURSE*sizeof(WORD);
  MALLOC((void *)dSrcMark,WORD,dSrcMarkSizeByte);
  dMarkTypeSizeByte=DMAX_PROG_RECURSE*sizeof(BYTE);
  MALLOC((void *)dMarkType,BYTE,dMarkTypeSizeByte);

  /* allocate our stack */
  dStackSizeByte=DMAX_PROG_RECURSE*sizeof(WORD);
  MALLOC((void *)dStack,WORD,dStackSizeByte);

  /* And our "else" statement stack */
/*  dStackElseSizeByte=DMAX_PROG_RECURSE*sizeof(WORD);
  MALLOC((void *)dStackElse,WORD,dStackElseSizeByte);*/
}

/* Take in a STR and free any embedded STR pointers */
void DecompStrFree(STR *ddComp) {
  BYTE dInstruction;  /* instruction we're looking at */
  void *dPtr;         /* general pointer - to STR or something */

  /* Note: This proc has to be re-entrant to a certain degree. Unfortunately, */
  /* this proc is not designed to be re-entrant. Therefore, we compromize     */
  /* (kludge). Since we should be freeing at most only 1 compiled code str    */
  /* (ie: there shouldn't be any embedded pointers to compiled code str's)    */
  /* we just check to see if we're code, and abort if not - and make sure the */
  /* code up and including the check are re-entrant. All the rest can suffer. */

  /* The first thing we have to do is check to see if what we've been passed */
  /* is actually compiled code.                                              */
  /* This would be the proper way to check if it's compiled:  */
/*  if ( (strcmp(ddComp->sText,CODE_PROG_HEADER))||
       ( (ddComp->sLen) <= (CODE_PROG_HEADER_LENGTH) )) {
    return;
  } */
  /* But to speed things up (because this proc is called to much), we settle */
  /* for this:                                                               */
  if (((ddComp->sText)[CODE_PROG_HEADER_LENGTH-1]!=0)||
      (ddComp->sLen<=CODE_PROG_HEADER_LENGTH))
    return;

  dThing=NULL;
  dComp=ddComp->sText;

  /* next, read the program code - search for str pointers */
  dCompOff=CODE_PROG_HEADER_LENGTH;
  while((dComp[dCompOff]!=CODE_BLK_CODE)&&
        (dComp[dCompOff]!=CODE_BLK_NULL)) {
    dCompOff++;
    dCompOff=DecompGetJump();
  }
  if (dComp[dCompOff]!=CODE_BLK_NULL) { /* We have CODE! */
    dCompOff++;
    dCompEnd=DecompGetJump();
    dCompStart=dCompOff;
    while(dCompOff<dCompEnd) { /* Great disassemble `while' */
      dInstruction=(dComp[dCompOff]&0xff);
      dCompOff++;
      switch(dInstruction) {
        case COP_PUSHPT: /* Here's our baby */
          /* Solaris doesn't like this */ 
          /* dPtr=*((void**)(&dComp[dCompOff])); */
          {
            unsigned long i;
            dPtr=NULL;
            for (i=0;i<CODE_PT_SIZE;i++)
              (unsigned long)(dPtr)|=
                ((unsigned long)(dComp[dCompOff+i]))<<(8*i);
          }
          dCompOff+=CODE_PT_SIZE;
          StrFree(Str(dPtr));
          break;
        case COP_COMMENT:
          dCompOff+=strlen(&dComp[dCompOff])+1;
          break;
        case COP_EXEC:
        case COP_EXECR: 
        case COP_GOTO:
        case COP_IFZ:
        case COP_WHILEZ:
        case COP_PUSHL:
          DecompGetJump();
          break;
        case COP_PUSHV1:
          dCompOff++;
          break;
        case COP_PUSHV2:
          dCompOff+=2;
          break;
        case COP_PUSHV:
        case COP_PUSHV4:
          dCompOff+=4;
          break;
/*        case COP_EQUSR:
        case COP_EQUSL:
        case COP_EQUOR:
        case COP_EQUXOR:
        case COP_EQUAND:
        case COP_EQUSUB:
        case COP_EQUADD:
        case COP_EQUMOD:
        case COP_EQUDIV:
        case COP_EQUMULT:
        case COP_EQU:
        case COP_BOR:
        case COP_BAND:
        case COP_OR:
        case COP_XOR:
        case COP_AND:
        case COP_BEQU:
        case COP_BNEQU:
        case COP_GEQ:
        case COP_GR:
        case COP_LEQ:
        case COP_LS:
        case COP_SR:
        case COP_SL:
        case COP_SUB:
        case COP_ADD:
        case COP_MOD:
        case COP_DIV:
        case COP_MULT:
        case COP_POP:
        case COP_NOP:
        case COP_NULL:
        case COP_BSUB:
        case COP_BADD:
        case COP_ASUB:
        case COP_AADD:
        case COP_COMP:
        case COP_NEG:
        case COP_NOT:
        case COP_TERM:
        case COP_PUSHG:
        case COP_PUSHP: */
        default:
          break;
      } /* decode switch */
    } /* great disassemble while */
  } /* if (we found code) */
}