/* avail
 *
 * Displays present memory statistics by type, size, in-use and available.
 *
 * Version 1.0 from (probably) Usenet; no author information available.
 *	- original program
 *
 * Version 2.0 by Thad Floryan, 23-July-1988
 *	- added private copy of AvailMem() to facilitate checking the "other"
 *	  types of "fast" RAM, and 32-bit wide RAM (as used with the various
 *	  68020 and 68030 accelerator cards).
 *	- re-arranged columns to be more useful.
 *	- fancy formatting of numbers with commas.
 *	- use AmigaDOS native I/O for speed and compactness
 *
 * Compiling and linking instructions (Manx):
 *
 *	CLI> cc avail
 *	CLI> ln avail -lc
 */

#include <stdio.h>
#include <exec/types.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

extern struct DosLibrary *DOSBase;
extern struct ExecBase *SysBase;

extern void FreeMem(), Forbid(), Permit(), Write();
extern char *AllocMem();
extern struct FileLock *Output();

#define WCHR(s)	*bufptr++ = s

char *version	= "Avail 2.0 (23-July-1988) Thad Floryan";

static struct FileLock *outlock;
static char *buf, *bufptr;

main()
{
    ULONG   maxsize(), memavail();
    void    pwcinum(), WSTR();

    ULONG   max1, max2, max3, max4, maxall;
    ULONG   avail1, avail2, avail3, avail4, availall;
    ULONG   largest1, largest2, largest3, largest4;

    outlock = Output();		/* initialize output handle     */

    buf = bufptr = AllocMem(400L, MEMF_CLEAR);

    Forbid();
       max1	= maxsize (MEMF_CHIP,		     0x00000000L, 0x00200000L);
       avail1	= memavail(MEMF_CHIP,		     0x00000000L, 0x00200000L);
       largest1	= memavail(MEMF_CHIP | MEMF_LARGEST, 0x00000000L, 0x00200000L);

       max2	= maxsize (MEMF_FAST,		     0x00200000L, 0x00C00000L);
       avail2	= memavail(MEMF_FAST,		     0x00200000L, 0x00C00000L);
       largest2	= memavail(MEMF_FAST | MEMF_LARGEST, 0x00200000L, 0x00C00000L);

       max3	= maxsize (MEMF_FAST,		     0x00C00000L, 0x01000000L);
       avail3	= memavail(MEMF_FAST,		     0x00C00000L, 0x01000000L);
       largest3	= memavail(MEMF_FAST | MEMF_LARGEST, 0x00C00000L, 0x01000000L);

       max4	= maxsize (MEMF_FAST,		     0x01000000L, 0x7FFFFFFFL);
       avail4	= memavail(MEMF_FAST,		     0x01000000L, 0x7FFFFFFFL);
       largest4	= memavail(MEMF_FAST | MEMF_LARGEST, 0x01000000L, 0x7FFFFFFFL);
    Permit();

    /*    ssss   dd,ddd,ddd  dd,ddd,ddd  dd,ddd,ddd  dd,ddd,ddd  */
    WSTR("Type         Size      In-Use   Available     Largest\nchip ");

	pwcinum(max1);
	pwcinum(max1-avail1);
	pwcinum(avail1);
	pwcinum(largest1);
    WSTR("\nfast ");
	pwcinum(max2);
	pwcinum(max2-avail2);
	pwcinum(avail2);
	pwcinum(largest2);
    WSTR("\n$C00 ");
	pwcinum(max3);
	pwcinum(max3-avail3);
	pwcinum(avail3);
	pwcinum(largest3);
    WSTR("\n>16M ");
	pwcinum(max4);
	pwcinum(max4-avail4);
	pwcinum(avail4);
	pwcinum(largest4);
    WSTR("\ntotal");
	maxall = max1 + max2 + max3 + max4;
	availall = avail1 + avail2 + avail3 + avail4;
	pwcinum(maxall);
	pwcinum(maxall - availall);
	pwcinum(availall);
    WCHR('\n'); WCHR('\000');

    Write(outlock, buf, (long)strlen(buf));
    FreeMem(buf, 400L);
}

/**************************************************************************
 * maxsize -- determine the total maximum size for all regions of the
 *	requested type.  This code MUST be executed while FORBIDDEN because
 *	it accesses shared system structures.
 **************************************************************************/

ULONG maxsize (t, lbound, ubound)
    ULONG t;
    ULONG lbound;
    ULONG ubound;
{
    ULONG size = 0L;
    struct MemHeader *mem;
    struct ExecBase *eb = SysBase;

    for (mem = (struct MemHeader *)eb->MemList.lh_Head;
	 mem ->mh_Node.ln_Succ;
	 mem = (struct MemHeader *)mem->mh_Node.ln_Succ)
    {
	if ((mem -> mh_Attributes & t)       &&
	    ((ULONG)mem->mh_Lower >= lbound) &&
	    ((ULONG)mem->mh_Lower <  ubound))
	{
	    size += ((ULONG) mem -> mh_Upper - (ULONG) mem -> mh_Lower);
	}
    }

    return size;
}

/**************************************************************************
 * memavail -- determine the total or largest size for all regions of the
 *	requested type.  This code MUST be executed while FORBIDDEN because
 *	it accesses shared system structures.
 **************************************************************************/

ULONG memavail (t, lbound, ubound)
    ULONG t;
    ULONG lbound;
    ULONG ubound;
{
    ULONG avail = 0L;
    struct MemHeader *mem;
    struct MemChunk *chunk;
    struct ExecBase *eb = SysBase;

    for (mem = (struct MemHeader *)eb->MemList.lh_Head;
	 mem ->mh_Node.ln_Succ;
	 mem = (struct MemHeader *)mem->mh_Node.ln_Succ)
    {
	if ((mem -> mh_Attributes & t)       &&
	    ((ULONG)mem->mh_Lower >= lbound) &&
	    ((ULONG)mem->mh_Lower <  ubound)   )
	{
	    if ((t & MEMF_LARGEST) && (mem->mh_First))
	    {
		for (chunk = (struct MemChunk *)mem->mh_First;
		     chunk;	/* bizzare termination for MemChunk chain */
		     chunk = (struct MemChunk *)chunk->mc_Next)
		{
		    if (chunk->mc_Bytes > avail)
		    {
			avail = chunk->mc_Bytes;
		    }
		}
	    }
	    else
	    {
		avail += (ULONG) mem -> mh_Free;
	    }
	}
    }

    return avail;
}

/*************************************************************************
 * pcinum  -- prints with commas a long integer number in width of 12
 *
 *************************************************************************/

void pwcinum(num)
    ULONG num;
{
    void pinum();

    if (num > 999999L)
    {
	pinum(4, ' ', num / 1000000L);
	WCHR(',');
	pinum(3, '0', (num % 1000000L)/1000L);
	WCHR(',');
	pinum(3, '0', num % 1000L);
    }
    else if (num > 999L)
    {
	pinum(8, ' ', num / 1000L);
	WCHR(',');
	pinum(3, '0', num % 1000L);
    }
    else
    {
	pinum(12, ' ', num);
    }
}

/*************************************************************************
 * pinum  --	displays a long integer in specified width with stated leading
 *		blank character treatment.
 *************************************************************************/

void pinum(width, leading, val)
    int   width;
    char  leading;
    ULONG val;
{
    char digbuf[15];
    register int i = 0;

    for (;;)
    {
	digbuf[i++] = (UBYTE)(val % 10L) + '0';
	val /= 10L;
	if (val == 0L) break;
    }
    if (width > i)
	for (width -= i; width; --width) WCHR(leading);

    for (; i > 0; --i) WCHR(digbuf[i-1]);
}

/*************************************************************************
 * WSTR  --  appends a string to currently-being-built display buffer
 *************************************************************************/

void WSTR(sptr)
    char  *sptr;
{
    while (*sptr) { WCHR(*sptr); ++sptr; }
}

