/************************************************************************
 *                                                                      *
 *                      Copyright (c) 1985 by                           *
 *              Digital Equipment Corporation, Maynard, MA              *
 *                      All rights reserved.                            *
 *                                                                      *
 *   The information in this software is subject to change  without     *
 *   notice  and should not be construed as a commitment by Digital     *
 *   Equipment Corporation.                                             *
 *                                                                      *
 *   Digital assumes no responsibility for the use  or  reliability     *
 *   of its software on equipment which is not supplied by Digital.     *
 *                                                                      *
 *   Redistribution and use in source and binary forms are permitted    *
 *   provided that the above copyright notice and this paragraph are    *
 *   duplicated in all such forms and that any documentation,           *
 *   advertising materials, and other materials related to such         *
 *   distribution and use acknowledge that the software was developed   *
 *   by Digital Equipment Corporation. The name of Digital Equipment    *
 *   Corporation may not be used to endorse or promote products derived *
 *   from this software without specific prior written permission.      *
 *   THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR     *
 *   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED     *
 *   WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.*
 *   Do not take internally. In case of accidental ingestion, contact   *
 *   your physician immediately.                                        *
 *                                                                      *
 ************************************************************************/

/* DO NOT INCLUDE "mnemosyne.h" !!! */
#include        <stdio.h>
#include        <ctype.h>
#include        <string.h>

static  char    rcsid[] = "$Header: rcs.c.mnemalys 1.4 91/04/05 17:21:19 gtoal Exp Locker: gtoal $";

/* added prototypes to stop warnings, ST Sept 94 */
char *strindex(char *s,int c);
int stringlen(char *s);

#include "mnemconf.h"

/* getting string.h/strings.h/strchr/index right is too much hassle */
char *strindex(s, c)
char *s;
int c;
{
  while (*s != '\0') {
    if (*s == c) return(s);
    s += 1;
  }
  return(NULL);
}

int stringlen(s)
char *s;
{
  int i = 0;
  while (*s != '\0') {
    i += 1;
    s += 1;
  }
  return(i);
}

#ifndef O_BINARY
#define O_BINARY 0
#endif

/*
post-processor to interpret memory allocation maps and search for
pointers that were allocated but never freed.

        Marcus J. Ranum, 1990. (mjr@decuac.dec.com)
*/


/*
simple and braindead, read in the ".lines" file, and store it in a
table by number. then read the pointer map, and crossref any unfreed
pointers. simple as dereferencing NULL...

this could use some cleaning and buffing, but it's damn effective as
it is. again, fancier symbol table routines would make this faster,
but who gives a damn? it only has to be faster than finding memory
leaks by hand...
*/

struct  xsym    {
        char    *dat;
        int     lnum;
        int     map;
        struct  xsym    *nxt;
};

int main(int argc, char **argv)
{
        register struct xsym    *sp;
        register struct xsym    *zp;
        struct  s_ptr   p;
        struct  xsym    *shash[HASHSIZ];
        char            inbuf[BUFSIZ];
        FILE            *lp;
        FILE            *fdtwo;
        int             fd;

        /* statistics */
        int             ptrcnt = 0;
        int             ptrbad = 0;
        int             ptrlos = 0;

        /* to chop up lines */
        char            *cpmap;
        char            *cpcalls;
        char            *cpave;
        char            *cplnum;
        char            *cpfnam;

        /* to find a particular map entry */
        int target = -1;


        for (argc--,argv++;argc;argc--,argv++) {
          if (**argv == '-') {
            /* parameter is a map entry number */
            if (isdigit(*++(*argv))) target = atoi(*argv);
            }
          }

        for(fd = 0; fd < HASHSIZ; fd++)
                shash[fd] = (struct xsym *)0;

        if((lp = fopen(LINESFILE,"r")) == (FILE *)0) {
                perror(LINESFILE);
                exit(1);
        }

	if((fdtwo = fopen(PTRFILE,"rb")) == (FILE *)0) {
                perror(PTRFILE);
                exit(1);
        }

        /* this is ugly, but I refuse to trust !@(#&U!@#&! sscanf() */
        while((cpmap = fgets(inbuf,sizeof(inbuf),lp)) != (char *)0) {
                if(inbuf[0] == '#')
                        continue;

                sp = (struct xsym *)malloc(sizeof(struct xsym));
                if(sp == (struct xsym *)0) {
                        perror("malloc");
                        exit(1);
                }
                sp->lnum = sp->map = 0;

                /* Changed from ungainly tabs to spaces -- GT */
                while (*cpmap == ' ') cpmap++;
                if((cpcalls = strindex(cpmap,' ')) != (char *)0) {
                        *cpcalls++ = '\0';
                        while (*cpcalls == ' ') cpcalls++;
                }

                if((cpave = strindex(cpcalls,' ')) != (char *)0) {
                        *cpave++ = '\0';
                        while (*cpave == ' ') cpave++;
                }

                if((cplnum = strindex(cpave,' ')) != (char *)0) {
                        *cplnum++ = '\0';
                        while (*cplnum == ' ') cplnum++;
                }

                if((cpfnam = strindex(cplnum,' ')) != (char *)0) {
                        *cpfnam++ = '\0';
                        while (*cpfnam == ' ') cpfnam++;
                }
                /* setup symbol */
                sp->map = atoi(cpmap);

                if(cplnum == (char *)0)
                        sp->lnum = -1;
                else
                        sp->lnum = atoi(cplnum);

                if(cpfnam != (char *)0) {
                        char    *x, *y;
                        if((x = strindex(cpfnam,'\n')) != (char *)0)
                                *x = '\0';

                        sp->dat = malloc((unsigned)(stringlen(cpfnam) + 1));
                        if(sp->dat == (char *)0) {
                                perror("malloc");
                                exit(1);
                        }
                        /*(void)strcpy(sp->dat,cpfnam);*/
                        x = sp->dat; y = cpfnam;
                        for (;;) {
                          *x = *y;
                          if (*y == '\0') break;
                          x += 1; y += 1;
                        }
                } else
                        sp->dat = "unknown";

                /* check to make sure it is not already in table */
                zp = shash[sp->map % HASHSIZ];
                while(zp != (struct xsym *)0) {
                        if(zp->map == sp->map) {
                                (void)fprintf(stderr,
                                "mnemalyse: duplicate map entry ignored");
                                (void)fprintf(stderr,
                                " (point at both %s and %s)\n",sp->dat,zp->dat);
                                (void)free(sp);

                                /* can't free dat - may not be malloced! */
                                sp = (struct xsym *)0;
                                break;
                        }
                        zp = zp->nxt;
                }

                /* shrug, link it in */
                if(sp != (struct xsym *)0) {
                        sp->nxt = shash[sp->map % HASHSIZ];
                        shash[sp->map % HASHSIZ] = sp;
                }
        }
        (void)fclose(lp);

        if (target != -1) {
          while(fread((void *)&(p.dsk),sizeof(p.dsk),1,fdtwo) == 1) {
                /* if the pointer was not deallocated, note it */
                if (ptrcnt == target) {
                        zp = shash[p.dsk.smap % HASHSIZ];
                        while(zp != (struct xsym *)0) {
                                if(zp->map == p.dsk.smap) {
                                    if (p.dsk.siz == 0) {
                                        printf(
                                          "map entry %d: freed pointer (last allocated at %s line:%d)\n",
                                          target, zp->dat,zp->lnum);
                                        return(0);
                                    } else {
                                        printf(
                                          "map entry %d: %d bytes allocated at %s line:%d\n",
                                          target, p.dsk.siz,zp->dat,zp->lnum);
                                        return(0);
                                    }
                                }
                                zp = zp->nxt;
                        }
                        ptrbad++;
                        ptrlos += p.dsk.siz;
                }
                ptrcnt++;
          }
          fprintf(stderr, "Cannot find map entry %d\n", target);
          return(1);
        }

        while(fread((void *)&(p.dsk),sizeof(p.dsk),1,fdtwo) == 1) {

                /* if the pointer was not deallocated, note it */
                if(p.dsk.siz != 0) {
                        zp = shash[p.dsk.smap % HASHSIZ];
                        while(zp != (struct xsym *)0) {
                                if(zp->map == p.dsk.smap) {
                                        printf("%d bytes missing %s line:%d\n",
                                        p.dsk.siz,zp->dat,zp->lnum);
                                }
                                zp = zp->nxt;
                        }
                        ptrbad++;
                        ptrlos += p.dsk.siz;
                }
                ptrcnt++;
        }

        printf("%d pointers, %d lost totalling %d bytes\n",
                ptrcnt,ptrbad,ptrlos);
        exit(0);
        return(0);
}