//
// revtree.c
//
// two routines for printing out ascii reverse call tree's
//
#include <stdio.h>
#include <string.h>
#if defined(OS2)
#define INCL_NOCOMMON
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSFILEMGR
#define INCL_DOSERRORS
#define INCL_DOSMISC
#include <os2.h>
#else
#include <windows.h>
#endif

#include <dos.h>


#include "hungary.h"
#include "bsc.h"
#include "bscsup.h"

// forward declarations
static BOOL FUsedInst(IINST iinst);
static VOID dRevTree(IINST iinst, WORD cuby);


// static variables
static BYTE *UbyBits = NULL;
static WORD cNest = 0;

VOID BSC_API
RevTreeInst (IINST iinst)
// emit the call tree starting from the given inst
//
{
    WORD iinstMac;
    int igrp;

    iinstMac = IinstMac();

    // allocate memory for bit array
    UbyBits = LpvAllocCb((WORD)(iinstMac/8 + 1));

    // no memory -- no call tree
    if (!UbyBits) return;

    igrp = iinstMac/8+1;

    while (--igrp>=0)
	UbyBits[igrp] = 0;

    cNest = 0;

    dRevTree(iinst, 1);

    FreeLpv(UbyBits);
}


static VOID 
dRevTree (IINST iinst, WORD cuby)
// emit the call tree starting from the given inst
//
// there are many block variables to keep the stack to a minimum...
{
    {
	ISYM isym;

	{
	    ATR atr;
	    TYP typ;

	    InstInfo(iinst, &isym, &typ, &atr);

	    if (typ > INST_TYP_LABEL)
		return;
	}

	    
	{
	    WORD i;
	    cNest++;
	    for (i = cNest; i; i--) BSCPrintf ("| ");
	}

	if (cuby > 1)
	    BSCPrintf ("%s[%d]", LszNameFrSym (isym), cuby);
	else
	    BSCPrintf ("%s", LszNameFrSym (isym));
    }

    if (FUsedInst(iinst)) {
	BSCPrintf ("...\n");
	cNest--;
	return;
    }
	
    BSCPrintf ("\n");

    {
	IUBY iuby, iubyMac;
	IINST iinstUby;

	UbyRangeOfInst(iinst, &iuby, &iubyMac);

	for (; iuby < iubyMac; iuby++) {
	    UbyInfo(iuby, &iinstUby, &cuby);
	    dRevTree (iinstUby, cuby);
	}
    }

    cNest--;
}

BOOL BSC_API
FRevTreeLsz(LSZ lszName)
// print out a call tree based on the given name
//
{
    IMOD imod;
    ISYM isym;

    cNest = 0;

    if (!lszName)
	return FALSE;

    {
	IINST iinstMac;
	int  igrp;

	iinstMac = IinstMac();

	// allocate memory for bit array
        UbyBits = LpvAllocCb((WORD)(iinstMac/8 + 1));

	// no memory -- no call tree
	if (!UbyBits) return FALSE;

	igrp = iinstMac/8+1;

	while (--igrp >= 0)
	    UbyBits[igrp] = 0;
    }

    if ((imod = ImodFrLsz (lszName)) != imodNil) {
	IMS ims, imsMac;

	MsRangeOfMod(imod, &ims, &imsMac);

	BSCPrintf ("%s\n", LszNameFrMod (imod));

	for ( ; ims < imsMac ; ims++)
	    dRevTree (IinstOfIms(ims), 1);
	
    	FreeLpv(UbyBits);
	return TRUE;
    }

    if ((isym = IsymFrLsz (lszName)) != isymNil) {
	IINST iinst, iinstMac;

	BSCPrintf ("%s\n", LszNameFrSym (isym));

	InstRangeOfSym(isym, &iinst, &iinstMac);

	for (; iinst < iinstMac; iinst++)
	    dRevTree (iinst, 1);
	
	FreeLpv(UbyBits);
	return TRUE;
    }

    FreeLpv(UbyBits);
    return FALSE;
}

static BOOL
FUsedInst(IINST iinst)
// return the status bit for this iinst and set it true
//
{
    WORD igrp;
    BOOL fOut;
    WORD mask;

    igrp = iinst / 8;
    mask = (1 << (iinst % 8));

    fOut = !!(UbyBits[igrp] & mask);
    UbyBits[igrp] |= mask;
    return fOut;
}