/*
 * PDBMM.C - memory management for the PDB library system
 *
 * Source Version: 9.0
 * Software Release #92-0043
 *
 */

#include "cpyright.h"

#include "pdb.h"

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_MK_PDB - THREADSAFE 
 *            - construct and return a pointer to a PDBFile */

PDBfile *_PD_mk_pdb(name)
   char *name;
   {PDBfile *file;
    SC_THREAD_ID(_t_index);

    file = FMAKE(PDBfile, "_PD_MK_PDB:file");
    if (file == NULL)
       return(NULL);

    file->stream     = NULL;
    file->name       = SC_strsavef(name, "char*:_PD_MK_PDB:name");
    file->type       = NULL;

    file->symtab     = SC_make_hash_table(HSZLARGE, NODOC);
    file->chart      = SC_make_hash_table(1, NODOC);
    file->host_chart = SC_make_hash_table(1, NODOC);
    file->attrtab    = NULL;
    file->mode       = 0;            /* read only, write only, read-write ? */

    file->maximum_size     = OFF_T_MAX;                       /* family info */
    file->previous_file    = NULL;

    file->flushed          = FALSE;                       /* born unflushed */
    file->virtual_internal = FALSE;                 /* disk file by default */
    file->current_prefix   = NULL;       /* read/write variable name prefix */
    file->system_version   = 0;

    file->default_offset = 0;           /* default offset for array indexes */
    file->major_order    = ROW_MAJOR_ORDER;

    file->track_pointers = TRUE;
    file->ptr_rd_list    = NULL;
    file->ptr_wr_list    = NULL;
    file->addr_rd_list   = NULL;
    file->addr_wr_list   = NULL;
    file->reta_rd_list   = NULL;

    file->max_rd_indx  = 0L;
    file->max_wr_indx  = 0L;
    file->rd_indx      = 0L;
    file->wr_indx      = 0L;

    file->std   = NULL;
    file->align = NULL;
    file->host_std   = _PD_copy_standard(_PD_INT_STANDARD(_t_index));
    file->host_align = _PD_copy_alignment(_PD_INT_ALIGNMENT(_t_index));

    file->n_dyn_spaces = 0L;

    file->symtaddr = 0;
    file->chrtaddr = 0;
    file->headaddr = 0;

    SC_mark(file->name, 1);
    SC_mark(file->symtab, 1);
    SC_mark(file->chart, 1);
    SC_mark(file->host_chart, 1);

    return(file);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_PDB - THREADSAFE
 *            - release the storage associated with the PDBfile */

void _PD_rl_pdb(file)
   PDBfile *file;
   {

    SFREE(file->date);

    PD_reset_ptr_list(file);

    if (file->attrtab != NULL)
       _PD_clr_table(file->attrtab, NULL);

    _PD_clr_table(file->host_chart, _PD_rl_defstr);
    _PD_clr_table(file->chart, _PD_rl_defstr);
    _PD_clr_table(file->symtab, _PD_rl_syment_d);

    _PD_rl_standard(file->std);
    _PD_rl_standard(file->host_std);
    _PD_rl_alignment(file->align);
    _PD_rl_alignment(file->host_align);

    if (file->previous_file != NULL)
       SFREE(file->previous_file);

    if (file->type != NULL)
       SFREE(file->type);

    SFREE(file->current_prefix);
    SFREE(file->name);
    SFREE(file);

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PD_ALLOC_ENTRY - allocate memory for the variable type */

byte *PD_alloc_entry(file, name)
   PDBfile *file;
   char *name;
   {syment *ep;
    byte *ret;

    ep = _PD_effective_ep(file, name, TRUE, NULL);
    if (ep == NULL)
       return(NULL);
    else
       {ret = _PD_alloc_entry(file, PD_entry_type(ep), PD_entry_number(ep));
	_PD_rl_syment_d(ep);
	return(ret);};}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_ALLOC_ENTRY - allocate memory for the variable type */

byte *_PD_alloc_entry(file, type, nitems)
   PDBfile *file;
   char *type;
   long nitems;
   {byte *vr;
    long len, bytespitem;
    defstr *dp;
    SC_THREAD_ID(_t_index);

    if (_PD_indirection(type))
       vr = (char *) FMAKE_N(char *, nitems, "_PD_ALLOC_ENTRY:char *");

    else
       {dp = PD_inquire_host_type(file, type);
        if (dp == NULL)
           {sprintf(PD_ERR(_t_index), "BAD TYPE %s - _PD_ALLOC_ENTRY", type);
            return(NULL);};

/* add extra space to chars - one for '\0' and one in case SC_firsttok
 * is applied to this string
 */
        if (strcmp(type, SC_CHAR_S) == 0)
           nitems += 2;

        bytespitem = dp->size;
        len = nitems * bytespitem;
        vr  = SC_alloc_na(len, 1L, "_PD_ALLOC_ENTRY:vr", FALSE);};

    return(vr);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_CLR_TABLE - THREADSAFE
 *               - release the storage associated with a homogeneous
 *               - hash table
 */

void _PD_clr_table(tab, rel)
   HASHTAB *tab;
   PFVoid rel;
   {int i, n;
    hashel **tb, *hp, *nxt;

    n  = tab->size;
    tb = tab->table;
    for (i = 0; i < n; i++)
        {for (hp = tb[i]; hp != NULL; hp = nxt)
             {nxt = hp->next;
              SFREE(hp->name);
              if (rel != NULL)
                 (*rel)(hp->def);
              SFREE(hp);};
         tb[i] = NULL;};

    SC_rl_hash_table(tab);

    return;}    

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_MK_STANDARD - THREADSAFE
 *                 - allocate, initialize and return a pointer to a
 *                 - data_standard
 */

data_standard *_PD_mk_standard()
   {data_standard *std;

    std = FMAKE(data_standard, "_PD_MK_STANDARD:std");

    std->bits_byte      = BITS_DEFAULT;
    std->ptr_bytes      = 0;
    std->short_bytes    = 0;
    std->short_order    = 0;
    std->int_bytes      = 0;
    std->int_order      = 0;
    std->long_bytes     = 0;
    std->long_order     = 0;
    std->longlong_bytes = 0;
    std->longlong_order = 0;
    std->float_bytes    = 0;
    std->float_format   = NULL;
    std->float_order    = NULL;
    std->double_bytes   = 0;
    std->double_format  = NULL;
    std->double_order   = NULL;

    return(std);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_COPY_STANDARD - THREADSAFE
 *                   - return a copy of the given data_standard */

data_standard *_PD_copy_standard(src)
   data_standard *src;
   {data_standard *std;
    int j, n;
    int *ostd, *osrc;
    long *fstd, *fsrc;

    std = FMAKE(data_standard, "_PD_COPY_STANDARD:std");

    std->bits_byte      = src->bits_byte;
    std->ptr_bytes      = src->ptr_bytes;
    std->short_bytes    = src->short_bytes;
    std->short_order    = src->short_order;
    std->int_bytes      = src->int_bytes;
    std->int_order      = src->int_order;
    std->long_bytes     = src->long_bytes;
    std->long_order     = src->long_order;
    std->longlong_bytes = src->longlong_bytes;
    std->longlong_order = src->longlong_order;
    std->float_bytes    = src->float_bytes;
    std->double_bytes   = src->double_bytes;

    n    = FORMAT_FIELDS;
    std->float_format  = FMAKE_N(long, n, "_PD_COPY_STANDARD:float_format");
    SC_mark(std->float_format, 1);
    fstd = std->float_format;
    fsrc = src->float_format;
    for (j = 0; j < n; j++, *(fstd++) = *(fsrc++));

    n    = (std->float_bytes > 0) ? std->float_bytes: -(std->float_bytes / std->bits_byte);
    std->float_order   = FMAKE_N(int,  n, "_PD_COPY_STANDARD:float_order");
    SC_mark(std->float_order, 1);
    ostd = std->float_order;
    osrc = src->float_order;
    for (j = 0; j < n; j++, *(ostd++) = *(osrc++));

    n    = FORMAT_FIELDS;
    std->double_format = FMAKE_N(long, n, "_PD_COPY_STANDARD:double_format");
    SC_mark(std->double_format, 1);
    fstd = std->double_format;
    fsrc = src->double_format;
    for (j = 0; j < n; j++, *(fstd++) = *(fsrc++));

    n    = (std->double_bytes > 0) ? std->double_bytes: -(std->double_bytes / std->bits_byte);
    std->double_order  = FMAKE_N(int,  n, "_PD_COPY_STANDARD:double_order");
    SC_mark(std->double_order, 1);
    ostd = std->double_order;
    osrc = src->double_order;
    for (j = 0; j < n; j++, *(ostd++) = *(osrc++));

    return(std);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_STANDARD - THREADSAFE
 *                 - release a data_standard */

void _PD_rl_standard(std)
   data_standard *std;
   {if (std != NULL)
       {SFREE(std->float_format);
        SFREE(std->float_order);
        SFREE(std->double_format);
        SFREE(std->double_order);

        SFREE(std);};

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_MK_ALIGNMENT - THREADSAFE
 *                  - allocate, initialize and return a pointer to a
 *                  - data_alignment
 */

data_alignment *_PD_mk_alignment(vals)
   char *vals;
   {data_alignment *align;

    align = FMAKE(data_alignment, "_PD_MK_ALIGNMENT:align");

    align->char_alignment     = vals[0];
    align->ptr_alignment      = vals[1];
    align->short_alignment    = vals[2];
    align->int_alignment      = vals[3];
    align->long_alignment     = vals[4];
    align->longlong_alignment = vals[4];  /* default-equal to long alignment*/
    align->float_alignment    = vals[5];
    align->double_alignment   = vals[6];

    if (strlen(vals) > 7)
       align->struct_alignment = vals[7];
    else
       align->struct_alignment = 0;

    return(align);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_COPY_ALIGNMENT - THREADSAFE
 *                    - return a copy of a data_alignment */

data_alignment *_PD_copy_alignment(src)
   data_alignment *src;
   {data_alignment *align;

    align = FMAKE(data_alignment, "_PD_COPY_ALIGNMENT:align");

    *align = *src;

    return(align);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_ALIGNMENT - THREADSAFE
 *                  - release a data_alignment */

void _PD_rl_alignment(align)
   data_alignment *align;
   {if (SC_arrlen(align) > 0)
       {SFREE(align);};

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PD_COPY_DIMS - make and return a copy of the given dimension list */

dimdes *PD_copy_dims(odims)
   dimdes *odims;
   {dimdes *od, *ndims, *prev, *next;

    prev  = NULL;
    ndims = NULL;
    
    for (od = odims; od != NULL; od = od->next)
        {next  = FMAKE(dimdes, "PD_COPY_DIMS:next");
         *next = *od;
	 next->next = NULL;

         if (ndims == NULL)
            ndims = next;
         else
	    {prev->next = next;
	     SC_mark(next, 1);};

         prev = next;};

    return(ndims);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PD_COPY_SYMENT - make and return a copy of the given syment */

syment *PD_copy_syment(osym)
   syment *osym;
   {int i, n;
    char *ntype;
    syment *nsym;
    symblock *nsp, *osp;
    dimdes *ndims;

    if (osym == NULL)
       return(NULL);

    nsym = FMAKE(syment, "PD_COPY_SYMENT:nsym");

    n   = PD_n_blocks(osym);
    osp = PD_entry_blocks(osym);
    nsp = FMAKE_N(symblock, n, "PD_COPY_SYMENT:blocks");
    for (i = 0; i < n; i++)
        {nsp[i] = osp[i];};

    ntype = SC_strsavef(PD_entry_type(osym),
			"char*:PD_COPY_SYMENT:type");
    ndims = PD_copy_dims(PD_entry_dimensions(osym));

    PD_entry_blocks(nsym)     = nsp;
    PD_entry_type(nsym)       = ntype;
    PD_entry_dimensions(nsym) = ndims;
    PD_entry_number(nsym)     = PD_entry_number(osym);
    PD_entry_indirects(nsym)  = PD_entry_indirects(osym);

    SC_mark(nsp, 1);
    SC_mark(ntype, 1);
    SC_mark(ndims, 1);

    return(nsym);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_MK_SYMENT - make and return a pointer to an entry
 *               - for the symbol table
 */

syment *_PD_mk_syment(type, numb, addr, indr, dims)
   char *type;
   long numb;
   off_t addr;
   symindir *indr;
   dimdes *dims;
   {syment *ep;
    symblock *sp;
    char *t;

    ep = FMAKE(syment, "_PD_MK_SYMENT:ep");
    sp = FMAKE(symblock, "_PD_MK_SYMENT:sp");

    PD_entry_blocks(ep) = sp;

    sp->number   = numb;
    sp->diskaddr = addr;

    if (type == NULL)
       t = NULL;
    else
       {t = SC_strsavef(type, "char*:_PD_MK_SYMENT:type");
	SC_mark(t, 1);};

    PD_entry_type(ep)       = t;
    PD_entry_number(ep)     = numb;
    PD_entry_dimensions(ep) = dims;

    if (indr == NULL)
       {symindir iloc;
        iloc.addr       = 0;
	iloc.n_ind_type = 0L;
	iloc.arr_offs = 0L;
	PD_entry_indirects(ep) = iloc;}

    else
       PD_entry_indirects(ep)  = *indr;

    SC_mark(sp, 1);
    SC_mark(dims, 1);

    return(ep);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_SYMENT_D - THREADSAFE
 *                 - reclaim the space of the given syment 
 *                 - including its dimensions
 */

void _PD_rl_syment_d(ep)
   syment *ep;
   {

    if (ep == NULL)
       return;
    
    _PD_rl_dimensions(PD_entry_dimensions(ep));
    _PD_rl_syment(ep);

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_SYMENT - THREADSAFE
 *               - reclaim the space of the given syment
 */

void _PD_rl_syment(ep)
   syment *ep;
   {

    SFREE(PD_entry_type(ep));
    SFREE(PD_entry_blocks(ep));
    SFREE(ep);

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_MK_DEFSTR - make a defstr entry for the structure chart */

defstr *_PD_mk_defstr(chrt, type, lst, sz, align, flg,
		      conv, ordr, formt, unsgned, onescmp)
   HASHTAB *chrt;
   char *type;
   memdes *lst;
   long sz;
   int align, flg, conv, *ordr;
   long *formt;
   int unsgned, onescmp;
   {defstr *dp;
    memdes *desc;
    int n;

    dp = FMAKE(defstr, "_PD_MK_DEFSTR:dp");

    dp->type       = SC_strsavef(type, "char*:_PD_MK_DEFSTR:type");
    dp->alignment  = align;
    dp->convert    = conv;
    dp->onescmp    = onescmp;
    dp->unsgned    = unsgned;
    dp->order_flag = flg;
    dp->order      = ordr;
    dp->format     = formt;
    dp->members    = lst;

    if (sz >= 0)
       {dp->size_bits = 0L;
	dp->size      = sz;}
    else
       {dp->size_bits = -sz;
	dp->size      = (-sz + 7) >> 3L;};

/* find the number of indirects */
    for (n = 0, desc = lst; desc != NULL; desc = desc->next)
        {if (_PD_indirection(desc->type))
            n++;

/* add the number of indirects of the member type
 * without this _PD_wr_syment won't properly write out
 * trees with nested structures in which there are layers
 * with no indirects!!!
 */
/* GOTCHA: make the reads/writes work when the counting goes this way
	 n += _PD_num_indirects(desc->type, chrt);
 */
         };

    dp->n_indirects = n;

    SC_mark(dp->type, 1);
    SC_mark(ordr, 1);
    SC_mark(formt, 1);

    return(dp);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_DEFSTR - THREADSAFE
 *               - free up the storage associated with a defstr */

void _PD_rl_defstr(dp)
   defstr *dp;
   {memdes *desc, *next;
    int *ord;
    long *frm;

    if (dp == NULL)
       return;

    if (SC_ref_count(dp) <= 1)
       {for (desc = dp->members; desc != NULL; desc = next)
	    {next = desc->next;
	     _PD_rl_descriptor(desc);};

	ord = dp->order;
	if ((ord != NULL) && (SC_arrlen(ord) > -1))
	   SFREE(dp->order);

	frm = dp->format;
	if ((frm != NULL) && (SC_arrlen(frm) > -1))
	   SFREE(dp->format);

	SFREE(dp->type);};

    SFREE(dp);

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PD_COPY_MEMBERS - copy a linked list of members */

memdes *PD_copy_members(desc)
   memdes *desc;
   {memdes *newm, *nnxt, *thism, *prevm;
    char *ms, *ts, *bs, *ns, *cs;
    dimdes *nd;

    newm  = NULL;
    prevm = NULL;
    for (thism = desc; thism != NULL; thism = thism->next)
        {nnxt = FMAKE(memdes, "PD_COPY_MEMBERS:nnxt");

         ms = SC_strsavef(thism->member,
			  "char*:PD_COPY_MEMBERS:member");
         ts = SC_strsavef(thism->type,
			  "char*:PD_COPY_MEMBERS:type");
         bs = SC_strsavef(thism->base_type,
			  "char*:PD_COPY_MEMBERS:base_type");
         ns = SC_strsavef(thism->name,
			  "char*:PD_COPY_MEMBERS:name");
         nd = PD_copy_dims(thism->dimensions);

         nnxt->member      = ms;
         nnxt->type        = ts;
         nnxt->base_type   = bs;
         nnxt->name        = ns;
         nnxt->dimensions  = nd;
         nnxt->next        = NULL;

         SC_mark(ms, 1);
         SC_mark(ts, 1);
         SC_mark(bs, 1);
         SC_mark(ns, 1);
         SC_mark(nd, 1);

         nnxt->member_offs = thism->member_offs;
         nnxt->cast_offs   = thism->cast_offs;
         nnxt->number      = thism->number;

         if (thism->cast_memb != NULL)
	    {cs = SC_strsavef(thism->cast_memb,
			      "char*:PD_COPY_MEMBERS:cast_memb");
	     nnxt->cast_memb  = cs;
             SC_mark(cs, 1);}
	 else
	    nnxt->cast_memb = NULL;

         if (newm == NULL)
            newm = nnxt;
         else
            {prevm->next = nnxt;
	     SC_mark(nnxt, 1);};

         prevm = nnxt;};

    return(newm);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_MK_DESCRIPTOR - build a MEMber DEScriptor out of the given string */

memdes *_PD_mk_descriptor(member, defoff)
   char *member;
   int defoff;
   {memdes *desc;
    char *ms, *ts, *bs, *ns, *p, *fp;
    char bf[MAXLINE];
    dimdes *nd;

    desc = FMAKE(memdes, "_PD_MK_DESCRIPTOR:desc");

/* get rid of any leading white space */
    for (p = member; strchr(" \t\n\r\f", *p) != NULL; p++);

    fp = SC_strstr(p, "(*");
    if (fp == NULL)
       {ms = SC_strsavef(p, "char*:_PD_MK_DESCRIPTOR:member");
	ts = _PD_member_type(p);
	bs = _PD_member_base_type(p);
	ns = _PD_member_name(p);
	nd = _PD_ex_dims(p, defoff);}

    else
       {ts = SC_strsave("function");
	bs = SC_strsave("function");
	ns = _PD_member_name(p);
	nd = NULL;
	sprintf(bf, "function %s", ns);
	ms = SC_strsavef(bf, "char*:_PD_MK_DESCRIPTOR:member");};
	
    desc->member     = ms;
    desc->type       = ts;
    desc->base_type  = bs;
    desc->name       = ns;
    desc->dimensions = nd;

    SC_mark(ms, 1);
    SC_mark(ts, 1);
    SC_mark(bs, 1);
    SC_mark(ns, 1);
    SC_mark(nd, 1);

    desc->number      = _PD_comp_num(desc->dimensions);
    desc->member_offs = -1L;
    desc->cast_offs   = -1L;
    desc->cast_memb   = NULL;
    desc->next        = NULL;

    return(desc);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_DESCRIPTOR - THREADSAFE
 *                   - release a MEMber DEScriptor */

void _PD_rl_descriptor(desc)
   memdes *desc;
   {
    if (desc == NULL)
       return;

    if (SC_ref_count(desc) <= 1)
       {SFREE(desc->member);
        SFREE(desc->name);
        SFREE(desc->type);
        SFREE(desc->base_type);
        SFREE(desc->cast_memb);

        _PD_rl_dimensions(desc->dimensions);}

    SFREE(desc);

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_MK_DIMENSIONS - build a DIMension DEScriptor out of the given numbers
 *                   -
 *                   - struct s_dimdes
 *                   -    {long index_min;
 *                   -     long index_max;
 *                   -     long number;
 *                   -     struct s_dimdes *next;};
 *                   -
 */

dimdes *_PD_mk_dimensions(mini, leng)
   long mini, leng;
   {dimdes *dims;

    dims            = FMAKE(dimdes, "_PD_MK_DIMENSIONS:dims");
    dims->index_min = mini;
    dims->index_max = mini + leng - 1L;
    dims->number    = leng;
    dims->next      = NULL;

    return(dims);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_RL_DIMENSIONS - THREADSAFE
 *                   - release a DIMension DEScriptor */

void _PD_rl_dimensions(dims)
   dimdes *dims;
   {dimdes *pp, *nxt;
    int nc;

    for (pp = dims; pp != NULL; pp = nxt)
        {nxt = pp->next;
         nc  = SC_ref_count(pp);
         SFREE(pp);
         if (nc > 1)
	    break;};

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
