
/* PDC Compiler - A Freely Distributable C Compiler for the Amiga
 *                Based upon prior work by Matthew Brandt and Jeff Lydiatt.
 *
 * PDC Compiler release 3.3 Copyright (C) 1989 Paul Petersen and Lionel Hummel.
 * PDC Software Distribution (C) 1989 Lionel Hummel and Paul Petersen.
 *
 * This code is freely redistributable upon the conditions that this 
 * notice remains intact and that modified versions of this file not be 
 * distributed as part of the PDC Software Distribution without the express
 * consent of the copyright holders.
 */

/*
 * Memmgt.c - Handles efficient and clean allocation of blocks of memory -
 * Cleanly deallocates local and global symbol entries
 */

#include        <stdio.h>
#include        "C.h"
#include        "Expr.h"
#include        "Gen.h"
#include        "Cglbdec.h"

#ifdef __PDC__
#ifdef unix
#define free    xfree    /* We do not presently mess with block deallocation */
#define calloc  xcalloc
#endif
#endif

extern char    *itoa();
extern char    *calloc();
extern char    *malloc();

struct blk {
    struct blk     *next;
    char            m[1];   /* memory area */
};

long            glbsize = 0,    /* size left in current global block    */
                locsize = 0,    /* size left in current local block     */
                glbindx = 0,    /* global index         */
                locindx = 0;    /* local index          */

long            glbwaste = 0;   /* Unused memory at the end of the block */
long            locwaste = 0;   /* Unused memory at the end of the block */

long            glballoc = 0;   /* Number of times calloc is called     */
long            localloc = 0;   /* Number of times calloc is called     */

struct blk     *locblk = NULL,  /* pointer to local block       */
               *glbblk = NULL;  /* pointer to global block      */

char           *
xalloc(siz)
    int             siz;
{
    struct blk     *bp;
    char           *rv, *mem;
    extern char    *calloc();

    if (siz & 1)        /* if odd size */
        siz += 1;   /* make it even */

    if (siz > 2048) {
        fputs("DIAG -- xalloc, size greater than 2048\n", stderr);
        exit(1);
    }

    if (global_flag) {
        if (glbsize > siz) {
            rv = &(glbblk->m[glbindx]);
            glbsize -= siz;
            glbindx += siz;
            mem = (char *) rv;
            goto done;
        }
        else {
            glbwaste += glbsize;
            ++glballoc;
            bp = (struct blk *) malloc( sizeof(struct blk) + 2047 );
            if (bp == NULL) {
                fputs(" not enough memory.\n", stderr);
                exit(1);
            }
            bzero( bp, sizeof(struct blk) + 2047 );
            bp->next = glbblk;
            glbblk = bp;
            glbsize = 2048 - siz;
            glbindx = siz;
            mem = (char *) glbblk->m;
            goto done;
        }
    }
    else {
        if (locsize > siz) {
            rv = &(locblk->m[locindx]);
            locsize -= siz;
            locindx += siz;
            mem = (char *) rv;
            goto done;
        }
        else {
            locwaste += locsize;
            ++localloc;
            bp = (struct blk *) malloc( sizeof(struct blk) + 2047 );
            if (bp == NULL) {
                fputs(" not enough local memory.\n", stderr);
                exit(1);
            }
            bzero( bp, sizeof(struct blk) + 2047 );
            bp->next = locblk;
            locblk = bp;
            locsize = 2048 - siz;
            locindx = siz;
            mem = (char *) locblk->m;
            goto done;
        }
    }
done:
    if (mem == NULL) {
        fputs("DIAG -- NULL responce from xalloc\n", stderr);
    }
    return (mem);
}


void
release_local()
{
    struct blk     *bp1, *bp2;
    char            nbuf[132];
    int             blkcnt;

    if (lastfunc != NULL && lastfunc->name != NULL)
        strcpy(nbuf, lastfunc->name);
    else
        strcpy(nbuf, "**PDC**");

    locwaste += locsize;

    blkcnt = 0;
    bp1 = locblk;
    while (bp1 != NULL) {
        bp2 = bp1->next;
        free(bp1);
        ++blkcnt;
        bp1 = bp2;
    }
    locblk = 0;
    locsize = 0;
    lsyms.head = NULL;

    if (!Options.Quiet) {
        fputs(nbuf, stderr);
        fputs(" : ", stderr);
        fputs(itoa(blkcnt * 2048L), stderr);
        fputs(" bytes local tables.\n", stderr);
    }
}

void
release_global()
{
    struct blk     *bp1, *bp2;
    int             blkcnt;

    glbwaste += glbsize;

    bp1 = glbblk;
    blkcnt = 0;
    while (bp1 != NULL) {
        bp2 = bp1->next;
        free(bp1);
        ++blkcnt;
        bp1 = bp2;
    }
    glbblk = 0;
    glbsize = 0;
    gsyms.head = NULL;  /* clear global symbol table */
    strtab = NULL;      /* clear literal table */

    if (!Options.Quiet) {
        fputs(" releasing ", stderr);
        fputs(itoa(blkcnt * 2048L), stderr);
        fputs(" bytes global tables.", stderr);
        fputs("\n", stderr);
    }
}
