/***************************************************
  memlist.c

  By: Stephen Vermeulen
      3635 Utah Dr. N.W.,
      Calgary, Alberta,
      CANADA, T2N 4A6

      (403) 282-7990.

  Completely public domain, for what its worth...

  A program to dump the systems memory list to the
  display or a file so that you have a snap shot of
  the list.  This program was written to try and
  understand an apparent memory fragmentation
  problem I was having once.

Syntax:

  memlist

    Will dump all the memory lists in the system to stdout.

  memlist > file

    Will redirect output to the desired file.

  memlist n

    Will only print out the lists for block n.  N should be 0, 1, ...
    On a 2.5Meg system block 0 will usually be FAST and block 1 will
    be CHIP

Output:

  Lots of lines like:

    memtype start end size running_total

  Where:

    memtype = 3    CHIP RAM; Header block
    memtype = 5    FAST RAM; Header block
    memtype = 64   Memory fragment within a memory block, the type of the
                   block is given by the previous Header block.
    start          Start address (decimal)
    end            End address (decimal)
    size           Block size (decimal bytes)
    running_total  Running total of number of bytes free in this
                   memory block.  That is total size of all previous
                   fragments since the last header block.

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

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <stdio.h>
#include <functions.h>

struct ExecBase *ExecBase;

#define MAX_LIST 1000
#define MEM_REGION (1L << 5)
#define MEM_CHUNK  (1L << 6)

long att[MAX_LIST];
ULONG start[MAX_LIST], end[MAX_LIST];

/*****************************************
  this function scans the system memory
  lists to see what is available and where
  it can be found.
******************************************/

long make_list()
{
  long i;
  struct MemHeader *mem, *loc;
  struct MemChunk *mc;

  for (mem = (struct MemHeader *) ExecBase->MemList.lh_Head, i = 0;
                      mem->mh_Node.ln_Succ && (i < MAX_LIST);
                      mem = (struct MemHeader *) mem->mh_Node.ln_Succ)
  {
    att[i]   = (long) mem->mh_Attributes;
    start[i] = (long) mem->mh_Lower;
    end[i]   = (long) mem->mh_Upper;
    ++i;
    for (mc = mem->mh_First; mc && (i < MAX_LIST); mc = mc->mc_Next)
    {
      att[i]   = MEM_CHUNK;
      start[i] = ((ULONG) mc) + 8L;
      end[i]   = ((ULONG) mc) + mc->mc_Bytes + 8L;
      ++i;
    }
  }
  return(i);
}

main(argc, argv)
short argc;
char *argv[];
{
  long i, upper, total;
  short blockn, j;

  if (argc == 2)
    sscanf(argv[1], "%d", &blockn);
  else
    blockn = -1;
  ExecBase = (struct ExecBase *) OpenLibrary("exec.library", 0L);
  if (!ExecBase) return;
  Forbid();
  upper = make_list();
  Permit();

  /***************************************
    Now print it to stdout for the record.
  ****************************************/

  if (blockn < 0)
  {
    for (i = 0; i < upper; ++i)
    {
      if (!(att[i] & MEM_CHUNK))
        total = 0;
      else
        total += end[i] - start[i];
      fprintf(stdout, "%ld %ld %ld %ld %ld\n", att[i], start[i], end[i], end[i] - start[i], total);
    }
  }
  else
  {
    j = -1;
    for (i = 0; i < upper; ++i)
    {
      if (!(att[i] & MEM_CHUNK))
      {
        total = 0;
        ++j;
      }
      else
        total += end[i] - start[i];
      if (j == blockn)
        fprintf(stdout, "%ld %ld %ld %ld %ld\n", att[i], start[i], end[i], end[i] - start[i], total);
    }
  }
  CloseLibrary(ExecBase);
}


