/*
 * PDBNET.C - routines to run over networks (special stuff)
 *
 * Routines and Usage:
 *
 *   PN_target   - returns a structure chart for the target machine
 *               - given the apropriate data_standard and data_alignment
 *               - used either to target remote machine as source or sink
 *               - (see PN_conv_in and PN_conv_out)
 *
 *   PN_open     - open a PDBfile which encapsulates a memory buffer
 *               - into and out of which all IO goes
 *
 *   PN_close    - close a PDBfile which was opened by PN_open
 *
 *   PN_defstr   - defines data structures to the two relevant structure
 *               - charts (host chart and target chart)
 *
 *   PN_conv_in  - convert the data in the input buffer which is in the
 *               - format of the remote machine (from which it has been read)
 *               - to the format of the host machine and place it in the
 *               - output buffer
 *
 *   PN_conv_out - convert the data in the output buffer which is in the
 *               - format of the host machine (from which it will be written)
 *               - to the format of the remote machine and place it in the
 *               - output buffer
 *
 *   PN_sizeof   - return the size of an item of the specified type
 *               - on the target machine (this is a macro)
 *
 *  These routines do NO network communications, they are provided so that
 *  PDBLib's data conversion and structured data handling facilities can
 *  be integrated with any network communication software.
 *
 * Source Version: 9.0
 * Software Release #92-0043
 *
 */

#include "cpyright.h"

#include "pdb.h"

typedef struct BF_FILE_s BF_FILE;

struct BF_FILE_s
   {long length;
    SC_address addr;
    SC_address bf;};

typedef struct s_file_static FILE_STATIC;

struct s_file_static
   {PFfopen        pio_open_save;
    PFftell        pio_tell_save;
    PFfread        pio_read_save;
    PFfwrite       pio_write_save;
    PFsetvbuf      pio_setvbuf_save;
    PFfclose       pio_close_save;
    PFfseek        pio_seek_save;
    PFfprintf      pio_printf_save;
    PFfputs        pio_puts_save;
    PFfgetc        pio_getc_save;
    PFungetc       pio_ungetc_save;
    PFfflush       pio_flush_save;
    PFfgets        pio_gets_save;
    HASHTAB        *_PN_host_chart;
    data_standard  *_PN_host_std;
    data_alignment *_PN_host_align;};
    
#define MEM(x)   ((x)->addr.memaddr)
#define DISK(x)  ((x)->addr.mdiskaddr)

#ifdef HAVE_THREADS

static FILE_STATIC
 *_PD_net_static = NULL;

#define PIO_OPEN_SAVE(x)    _PD_net_static[x].pio_open_save
#define PIO_TELL_SAVE(x)    _PD_net_static[x].pio_tell_save
#define PIO_READ_SAVE(x)    _PD_net_static[x].pio_read_save
#define PIO_WRITE_SAVE(x)   _PD_net_static[x].pio_write_save
#define PIO_SETVBUF_SAVE(x) _PD_net_static[x].pio_setvbuf_save
#define PIO_CLOSE_SAVE(x)   _PD_net_static[x].pio_close_save
#define PIO_SEEK_SAVE(x)    _PD_net_static[x].pio_seek_save
#define PIO_PRINTF_SAVE(x)  _PD_net_static[x].pio_printf_save
#define PIO_PUTS_SAVE(x)    _PD_net_static[x].pio_puts_save
#define PIO_GETC_SAVE(x)    _PD_net_static[x].pio_getc_save
#define PIO_UNGETC_SAVE(x)  _PD_net_static[x].pio_ungetc_save
#define PIO_FLUSH_SAVE(x)   _PD_net_static[x].pio_flush_save
#define PIO_GETS_SAVE(x)    _PD_net_static[x].pio_gets_save
#define _PN_HOST_CHART(x)  _PD_net_static[x]._PN_host_chart
#define _PN_HOST_STD(x)    _PD_net_static[x]._PN_host_std
#define _PN_HOST_ALIGN(x)  _PD_net_static[x]._PN_host_align

#else

static PFfopen   pio_open_save = NULL;
static PFftell   pio_tell_save = NULL;
static PFfread   pio_read_save = NULL;
static PFfwrite  pio_write_save = NULL;
static PFsetvbuf pio_setvbuf_save = NULL;
static PFfclose  pio_close_save = NULL;
static PFfseek   pio_seek_save = NULL;
static PFfprintf pio_printf_save = NULL;
static PFfputs   pio_puts_save = NULL;
static PFfgetc   pio_getc_save = NULL;
static PFungetc  pio_ungetc_save = NULL;
static PFfflush  pio_flush_save = NULL;
static PFfgets   pio_gets_save = NULL;

static HASHTAB
 *_PN_host_chart = NULL;

static data_standard
 *_PN_host_std = NULL;

static data_alignment
 *_PN_host_align = NULL;

#define PIO_OPEN_SAVE(x)    pio_open_save
#define PIO_TELL_SAVE(x)    pio_tell_save
#define PIO_READ_SAVE(x)    pio_read_save
#define PIO_WRITE_SAVE(x)   pio_write_save
#define PIO_SETVBUF_SAVE(x) pio_setvbuf_save
#define PIO_CLOSE_SAVE(x)   pio_close_save
#define PIO_SEEK_SAVE(x)    pio_seek_save
#define PIO_PRINTF_SAVE(x)  pio_printf_save
#define PIO_PUTS_SAVE(x)    pio_puts_save
#define PIO_GETC_SAVE(x)    pio_getc_save
#define PIO_UNGETC_SAVE(x)  pio_ungetc_save
#define PIO_FLUSH_SAVE(x)   pio_flush_save
#define PIO_GETS_SAVE(x)    pio_gets_save
#define _PN_HOST_CHART(x)  _PN_host_chart
#define _PN_HOST_STD(x)    _PN_host_std
#define _PN_HOST_ALIGN(x)  _PN_host_align

#endif
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PN_BOPEN - prepare the pseudo file */

static FILE *_PN_bopen(name, mode)
   char *name, *mode;
   {BF_FILE *fp;

    fp = FMAKE(BF_FILE, "_PN_BOPEN:fp");

    fp->length       = SC_arrlen(name);
    fp->bf.memaddr   = name;
    fp->addr.memaddr = name;

    return((FILE *) fp);}

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

/* _PN_BSETVBUF - set the pseudo file buffer
 *              - binds to pio_setvbuf_hook
 */

static int _PN_bsetvbuf(stream, bf, type, size)
   FILE *stream;
   char *bf;
   int type;
   size_t size;
   {BF_FILE *fp;
    int ret;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    ret = TRUE;
    if (fp == NULL)
       ret = FALSE;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       ret = setvbuf(stream, bf, type, size);

    return(ret);}

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

/* _PN_BCLOSE - close the pseudo file
 *            - binds to pio_close_hook
 */

static int _PN_bclose(stream)
   FILE *stream;
   {BF_FILE *fp;
    int ret;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    ret = 0;
    if (fp == NULL)
       ret = EOF;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       ret = fclose(stream);

    SFREE(fp);

    return(ret);}

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

/* _PN_BFLUSH - do an fflush on the pseudo file
 *            - binds to pio_flush_hook
 */

static int _PN_bflush(stream)
   FILE *stream;
   {int ret;
    BF_FILE *fp;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    ret = FALSE;
    if (fp == NULL)
       ret = TRUE;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       ret = fflush(stream);

    return(ret);}

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

/* _PN_BTELL - do an ftell on the pseudo file
 *           - binds to pio_tell_hook
 */

static off_t _PN_btell(stream)
   FILE *stream;
   {BF_FILE *fp;
    off_t addr;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    addr = -1;
    if (fp == NULL)
       addr = -1;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       addr = F_TELL(stream);

    else
       addr = DISK(fp);

    return(addr);}

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

/* _PN_BSEEK - do an fseek on the pseudo file
 *           - binds to pio_seek_hook
 */

static int _PN_bseek(stream, addr, offset)
   FILE *stream;
   off_t addr;
   int offset;
   {int ret;
    BF_FILE *fp;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    ret = 0;
    if (fp == NULL)
       ret = -1;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       ret = F_SEEK(stream, addr, offset);

    else
       {switch (offset)
           {case SEEK_SET :
		 DISK(fp) = addr;
                 break;

            case SEEK_CUR :
		 DISK(fp) += addr;
                 break;

            case SEEK_END :
		 DISK(fp) = fp->bf.mdiskaddr + fp->length + addr;
                 break;

            default :
	         ret = -1;
	         break;};};

    return(ret);}

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

/* _PN_BREAD - do an fread on the pseudo file
 *           - binds to pio_read_hook
 */

static size_t _PN_bread(s, nbi, ni, stream)
   char *s;
   size_t nbi, ni;
   FILE *stream;
   {BF_FILE *fp;
    size_t nbw;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    nbw = nbi*ni;
    if (fp == NULL)
       nbw = 0;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       nbw = fread(s, nbi, ni, stream);

    else
       {memcpy(s, MEM(fp), nbw);

/* adjust the current address */
        DISK(fp) += nbw;};

    return(ni);}

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

/* _PN_BWRITE - do an fwrite on the pseudo file
 *            - binds to pio_write_hook
 */

static size_t _PN_bwrite(s, nbi, ni, stream)
   char *s;
   size_t nbi, ni;
   FILE *stream;
   {long nbw;
    BF_FILE *fp;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    nbw = nbi*ni;
    if ((fp == NULL) || (nbi*ni == 0))
       nbw = 0;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       nbw = fwrite(s, nbi, ni, stream);

    else
       {memcpy(MEM(fp), s, nbw);

/* adjust the current address */
        DISK(fp) += nbw;};

    return(ni);}

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

/* _PN_BPRINTF - do an fprintf on the pseudo file
 *             - binds to pio_puts_hook
 */

#ifdef PCC

int _PN_bprintf(fp, fmt, va_alist)
   FILE *fp;
   char *fmt;
   va_dcl

#endif

#ifdef ANSI

int _PN_bprintf(FILE *fp, char *fmt, ...)

#endif

   {size_t ni, nw;
    char _PN_bf[LRG_TXT_BUFFER];
    SC_THREAD_ID(_t_index);

    nw = 0;

    if (fp != NULL)
       {SC_VA_START(fmt);
	SC_VSPRINTF(_PN_bf, fmt);
	SC_VA_END;

	ni = strlen(_PN_bf);
	nw = pio_write(_PN_bf, (size_t) 1, ni, fp);};

    return((int) nw);}

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

/* _PN_BPUTS - do an fputs on the pseudo file
 *           - binds to pio_puts_hook
 */

static int _PN_bputs(s, stream)
   char *s;
   FILE *stream;
   {int nc;
    long nbw;
    BF_FILE *fp;
    SC_THREAD_ID(_t_index);
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    if (fp == NULL)
       nbw = 0;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       nbw = fputs(s, stream);

    else
       {nc  = strlen(s);
	nbw = pio_write(s, 1, nc, stream);};

    return(nbw);}

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

/* _PN_BGETS - do an fgets on the pseudo file
 *           - binds to pio_gets_hook
 */

static char *_PN_bgets(s, nc, stream)
   char *s;
   int nc;
   FILE *stream;
   {int ns;
    char *pb, *ps;
    BF_FILE *fp;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    ps = NULL;
    if (fp == NULL)
       ps = NULL;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       ps = fgets(s, nc, stream);

    else
       {pb = strchr(MEM(fp), '\n');
	if (pb != NULL)
	   {ns = pb - MEM(fp) + 1;
	    ns = min(nc, ns);
	    memcpy(s, MEM(fp), ns);
	    s[ns] = '\0';

/* adjust the local idea of the current disk address */
	    DISK(fp) += ns;};};

    return(ps);}

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

/* _PN_BGETC - do an fgetc on the pseudo file
 *           - binds to pio_getc_hook
 */

static int _PN_bgetc(stream)
   FILE *stream;
   {int c;
    BF_FILE *fp;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    if (fp == NULL)
       c = EOF;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       c = fgetc(stream);

    else
       c = *MEM(fp)++;

    return(c);}

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

/* _PN_BUNGETC - do an fungetc on the pseudo file
 *             - binds to pio_ungetc_hook
 */

static int _PN_bungetc(c, stream)
   int c;
   FILE *stream;
   {BF_FILE *fp;
#ifdef HAVE_THREADS
    PD_Pfile *pfile;

    pfile = (PD_Pfile *) stream;
    fp    = (BF_FILE *) pfile->stream;
#else
    fp  = (BF_FILE *) stream;
#endif

    if (fp == NULL)
       c = 0;

    else if ((stream == stdout) || (stream == stdin) || (stream == stderr))
       c = ungetc(c, stream);

    else
       MEM(fp)--;

    return(c);}

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

/* _PN_SAVE_HOOKS - save the current pio_hooks */

static void _PN_save_hooks()
   {SC_THREAD_ID(_t_index);

    if (PIO_OPEN_SAVE(_t_index) == NULL)
       {PIO_OPEN_SAVE(_t_index)    = PIO_OPEN_HOOK(_t_index);
        PIO_TELL_SAVE(_t_index)    = PIO_TELL_HOOK(_t_index);
	PIO_READ_SAVE(_t_index)    = PIO_READ_HOOK(_t_index);
	PIO_WRITE_SAVE(_t_index)   = PIO_WRITE_HOOK(_t_index);
	PIO_PRINTF_SAVE(_t_index)  = PIO_PRINTF_HOOK(_t_index);
	PIO_SETVBUF_SAVE(_t_index) = PIO_SETVBUF_HOOK(_t_index);
	PIO_CLOSE_SAVE(_t_index)   = PIO_CLOSE_HOOK(_t_index);
	PIO_SEEK_SAVE(_t_index)    = PIO_SEEK_HOOK(_t_index);
	PIO_PUTS_SAVE(_t_index)    = PIO_PUTS_HOOK(_t_index);
	PIO_GETC_SAVE(_t_index)    = PIO_GETC_HOOK(_t_index);
	PIO_UNGETC_SAVE(_t_index)  = PIO_UNGETC_HOOK(_t_index);
	PIO_FLUSH_SAVE(_t_index)   = PIO_FLUSH_HOOK(_t_index);
	PIO_GETS_SAVE(_t_index)    = PIO_GETS_HOOK(_t_index);};

    PIO_OPEN_HOOK(_t_index)    = (PFfopen) _PN_bopen;
    PIO_TELL_HOOK(_t_index)    = (PFftell) _PN_btell;
    PIO_READ_HOOK(_t_index)    = (PFfread) _PN_bread;
    PIO_WRITE_HOOK(_t_index)   = (PFfwrite) _PN_bwrite;
    PIO_PRINTF_HOOK(_t_index)  = (PFfprintf) _PN_bprintf;
    PIO_SETVBUF_HOOK(_t_index) = (PFsetvbuf) _PN_bsetvbuf;
    PIO_CLOSE_HOOK(_t_index)   = (PFfclose) _PN_bclose;
    PIO_SEEK_HOOK(_t_index)    = (PFfseek) _PN_bseek;
    PIO_PUTS_HOOK(_t_index)    = (PFfputs) _PN_bputs;
    PIO_GETC_HOOK(_t_index)    = (PFfgetc) _PN_bgetc;
    PIO_UNGETC_HOOK(_t_index)  = (PFungetc) _PN_bungetc;
    PIO_FLUSH_HOOK(_t_index)   = (PFfflush) _PN_bflush;
    PIO_GETS_HOOK(_t_index)    = (PFfgets) _PN_bgets;

    return;}

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

/* _PN_RESTORE_HOOKS - restore the pio_hooks */

static void _PN_restore_hooks()
   {SC_THREAD_ID(_t_index);

    PIO_OPEN_HOOK(_t_index)    = PIO_OPEN_SAVE(_t_index);
    PIO_TELL_HOOK(_t_index)    = PIO_TELL_SAVE(_t_index);
    PIO_READ_HOOK(_t_index)    = PIO_READ_SAVE(_t_index);
    PIO_WRITE_HOOK(_t_index)   = PIO_WRITE_SAVE(_t_index);
    PIO_SETVBUF_HOOK(_t_index) = PIO_SETVBUF_SAVE(_t_index);
    PIO_CLOSE_HOOK(_t_index)   = PIO_CLOSE_SAVE(_t_index);
    PIO_SEEK_HOOK(_t_index)    = PIO_SEEK_SAVE(_t_index);
    PIO_PRINTF_HOOK(_t_index)  = PIO_PRINTF_SAVE(_t_index);
    PIO_PUTS_HOOK(_t_index)    = PIO_PUTS_SAVE(_t_index);
    PIO_GETC_HOOK(_t_index)    = PIO_GETC_SAVE(_t_index);
    PIO_UNGETC_HOOK(_t_index)  = PIO_UNGETC_SAVE(_t_index);
    PIO_FLUSH_HOOK(_t_index)   = PIO_FLUSH_SAVE(_t_index);
    PIO_GETS_HOOK(_t_index)    = PIO_GETS_SAVE(_t_index);

    return;}

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

/* _PN_SIZEOF - sizeof operator for PDBNet */

static int _PN_sizeof(s)
   char *s;
   {SC_THREAD_ID(_t_index);

    if (_PN_HOST_CHART(_t_index) != NULL)
       return(_PD_lookup_size(s, _PN_HOST_CHART(_t_index)));

    else
       return(SC_sizeof(s));}

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

/* PN_CONV_IN - convert from one machine format to another after input
 *            - from a remote host with different architecture
 *            - NITEMS of type, TYPE, from IN and put them in OUT
 *            - all additional information comes from OUT_CHART
 */

void PN_conv_in(out, in, type, nitems, in_chart)
   byte *out, *in;
   char *type;
   long nitems;
   HASHTAB *in_chart;
   {long ino, outo;
    data_standard *istd;
    SC_THREAD_ID(_t_index);

    switch (setjmp(_PD_TRACE_ERR(_t_index)))
       {case ABORT    : return;
        case ERR_FREE : return;
        default       : memset(PD_ERR(_t_index), 0, MAXLINE);
                        break;};

    ino  = outo = 0L;
    istd = (data_standard *) SC_def_lookup("standard", in_chart);

    PD_convert((char **) &out, (char **) &in, type, type, nitems,
               istd, _PN_HOST_STD(_t_index), _PN_HOST_STD(_t_index),
               &ino, &outo, in_chart, _PN_HOST_CHART(_t_index), 0, PD_TRACE);

    return;}

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

/* PN_CONV_OUT - convert from one machine format to another before output
 *             - to a remote host with different architecture
 *             - NITEMS of type, TYPE, from IN and put them in OUT
 *             - all additional information comes from OUT_CHART
 */

void PN_conv_out(out, in, type, nitems, out_chart)
   byte *out, *in;
   char *type;
   long nitems;
   HASHTAB *out_chart;
   {long ino, outo;
    data_standard *ostd;
    SC_THREAD_ID(_t_index);

    switch (setjmp(_PD_TRACE_ERR(_t_index)))
       {case ABORT    : return;
        case ERR_FREE : return;
        default       : memset(PD_ERR(_t_index), 0, MAXLINE);
                        break;};

    ino  = outo = 0L;
    ostd = (data_standard *) SC_def_lookup("standard", out_chart);

    PD_convert((char **) &out, (char **) &in, type, type, nitems,
               _PN_HOST_STD(_t_index), ostd, _PN_HOST_STD(_t_index), &ino, &outo,
               _PN_HOST_CHART(_t_index), out_chart, 0, PD_TRACE);

    return;}

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

/* PN_TARGET - allocate, initialize, and return a structure chart
 *           - for the associated standard and alignemnt
 *           - for network PDB
 */

HASHTAB *PN_target(std, align)
   data_standard *std;
   data_alignment *align;
   {HASHTAB *chart;
    SC_THREAD_ID(_t_index);

/* if the first time initialize some stuff */
    if (PD_DEFSTR_S == NULL)
       {LAST           = FMAKE(int, "PN_TARGET:LAST");
        *LAST          = 0;
        PD_DEFSTR_S    = SC_strsavef("defstr *", "char*:PN_TARGET:defstr");
        PD_SYMENT_S    = SC_strsavef("syment *", "char*:PN_TARGET:syment");
        PD_STANDARD_S  = SC_strsavef("data_standard", "char*:PN_TARGET:ds");
        PD_ALIGNMENT_S = SC_strsavef("data_alignment",
                                        "char*:PN_TARGET:da");};

/* initialize the host chart the first time only */
    if (_PN_HOST_STD(_t_index) == NULL)
       {_PN_HOST_STD(_t_index)   = _PD_copy_standard(_PD_INT_STANDARD(_t_index));
	_PN_HOST_ALIGN(_t_index) = _PD_copy_alignment(_PD_INT_ALIGNMENT(_t_index));
        _PN_HOST_CHART(_t_index) = PN_target(_PN_HOST_STD(_t_index), _PN_HOST_ALIGN(_t_index));};

/* initialize the chart */
    chart  = SC_make_hash_table(1, NODOC);

    _PD_setup_chart(chart, std,
		    _PN_HOST_STD(_t_index), align, _PN_HOST_ALIGN(_t_index), TRUE);

/* special hack for jollies and to save typing */
    SC_install("standard", std, PD_STANDARD_S, chart);
    SC_install("alignment", align, PD_ALIGNMENT_S, chart);

    return(chart);}

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

/* PN_DEFSTR - a structure definition mechanism for PDBLib
 *           -
 *           - sample syntax:
 *           -
 *           -   PN_defstr(<PDB file>, "<struct name>",
 *           -                         "<member1>", "<member2>",
 *           -                 ...     "<membern>", LAST);
 *           -
 *           - where
 *           - 
 *           -   <member> := <primitive type> <member name>[(<dimensions>)] |
 *           -               <derived type> <member name>[(<dimensions>)]
 *           -
 *           -   <dimensions> := <non-negative int> |
 *           -                   <non-negative int>,<dimensions> |
 *           -                   <non-negative int>, <dimensions> |
 *           -                   <non-negative int> <dimensions>
 *           -
 *           -   <primitive type> := short | integer | long | float |
 *           -                       double | char | short * | integer *
 *           -                       long * | float * | double * | char *
 *           - 
 *           -   <derived type> := any defstr'd type | any defstr'd type *
 *           -
 *           - LAST is a pointer to a integer zero and is specifically
 *           - allocated by PDBLib to be used to terminate argument lists
 *           - which consist of pointers
 *           -
 *           - Returns NULL if member types are unknown
 */

#ifdef PCC

defstr *PN_defstr(chart, name, align, defoff, va_alist)
   HASHTAB *chart;
   char *name;
   data_alignment *align;
   int defoff;
   va_dcl

#endif

#ifdef ANSI

defstr *PN_defstr(HASHTAB *chart, char *name, data_alignment *align,
                  int defoff, ...)

#endif

   {char *nxt, *ptype, *type;
    defstr *dp;
    memdes *desc, *lst, *prev;
    SC_THREAD_ID(_t_index);

    SC_sizeof_hook = _PN_sizeof;

    SC_VA_START(defoff);

    prev   = NULL;
    lst    = NULL;
    for (nxt = SC_VA_ARG(char *); (int) *nxt != 0;
         nxt = SC_VA_ARG(char *))
        {desc  = _PD_mk_descriptor(nxt, defoff);
         type  = SC_strsavef(nxt, "char*:PN_DEFSTR:type");
         ptype = SC_firsttok(type, " \n");
         if (SC_lookup(ptype, chart) == NULL)
            if ((strcmp(ptype, name) != 0) || !_PD_indirection(nxt))
               {sprintf(PD_ERR(_t_index), "ERROR: %s BAD MEMBER TYPE - PN_DEFSTR\n",
                                nxt);
                return(NULL);};
         SFREE(type);
         if (lst == NULL)
            lst = desc;
         else
            prev->next = desc;
         prev = desc;};

    SC_VA_END;

/* install the type in both charts */
    dp = _PD_defstr_inst(name, lst, -1, NULL, NULL,
                         chart, _PN_HOST_CHART(_t_index),
                         align, _PN_HOST_ALIGN(_t_index), FALSE);
    if (dp == NULL)
       sprintf(PD_ERR(_t_index), "ERROR: CAN'T HANDLE PRIMITIVE TYPE - PN_DEFSTR\n");

    return(dp);}

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

/* PN_OPEN - create a special pseudo PDBfile and set all the
 *         - io hooks appropriately
 */

PDBfile *PN_open(fm, bf)
   PDBfile *fm;
   char *bf;
   {PDBfile *file;
    FILE *fp;
    SC_THREAD_ID(_t_index);

#ifdef HAVE_THREADS
    if (_PD_nthreads <= 0)
       PD_init_threads(1, NULL);
#endif

    _PN_save_hooks();

    switch (setjmp(_PD_CREATE_ERR(_t_index)))
       {case ABORT    : pio_close(fp);
	                _PN_restore_hooks();
                        return(NULL);
        case ERR_FREE : return(file);
        default       : memset(PD_ERR(_t_index), 0, MAXLINE);
                        break;};

    fp = pio_open(bf, BINARY_MODE_WPLUS);

    if (fp == NULL)
       PD_error("CAN'T CREATE FILE - PN_OPEN", PD_CREATE);

/* make the PDBfile */
    file = FMAKE(PDBfile, "PN_OPEN:file");
    if (file == NULL)
       PD_error("CAN'T ALLOCATE PDBFILE - PN_OPEN", PD_CREATE);

/* copy over stuff from the template file */
    *file = *fm;

    file->name             = SC_strsavef("pseudo", "char*:PN_OPEN:name");
    file->stream           = fp;
    file->mode             = PD_APPEND;

#ifdef HAVE_THREADS
    _PD_smp_init(file);
    fp = file->stream;
#endif

    file->chrtaddr         = pio_tell(fp);
    file->system_version   = PDB_SYSTEM_VERSION;
    file->date             = SC_date();
    file->virtual_internal = FALSE;
    file->current_prefix   = NULL;
    file->symtab           = SC_make_hash_table(HSZSMALL, NODOC);

#ifdef HAVE_THREADS
/* Create a directory to hold the symbol table entries
 * generated for pointees.
 */
    _PD_pfm_setaddr(file, file->chrtaddr);
#endif


    return(file);}

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

/* PN_CLOSE - close the special pseudo PDBfile and reset all the
 *          - io hooks
 */

int PN_close(file)
   PDBfile *file;
   {int ret;
    FILE *fp;
    SC_THREAD_ID(_t_index);

    fp  = file->stream;
    ret = TRUE;

    if (pio_close(fp) != 0)
       PD_error("CAN'T CLOSE FILE - PD_CLOSE", PD_CLOSE);

    _PN_restore_hooks();

/* free the space */
    PD_reset_ptr_list(file);

    _PD_clr_table(file->symtab, _PD_rl_syment_d);

#ifdef HAVE_THREADS
    _PD_smp_term(file);
#endif

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

    return(ret);}

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

/* PN_WRITE - write the given data to the special pseudo PDBfile */

int PN_write(file, type, nitems, vr)
   PDBfile *file;
   char *type;
   long nitems;
   byte *vr;
   {int ret;
    char bf[MAXLINE];

    PD_reset_ptr_list(file);

    sprintf(bf, "s[%ld]", nitems);

    ret = PD_write(file, bf, type, vr);

    return(ret);}

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

/* PN_READ - read the given data from the special pseudo PDBfile */

int PN_read(file, type, nitems, vr)
   PDBfile *file;
   char *type;
   long nitems;
   byte *vr;
   {int ret;
    char bf[MAXLINE];
    syment *ep;
    FILE *fp;
    SC_THREAD_ID(_t_index);

    PD_reset_ptr_list(file);

    fp = file->stream;

    sprintf(bf, "s");

    ep = _PD_mk_syment(type, nitems, pio_tell(fp), NULL, NULL);
    _PD_e_install(bf, ep, file->symtab, TRUE);

    ret = PD_read(file, bf, vr);

    return(ret);}

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

/* _PD_NET_PINIT - initialize the file static variables for
 *                 parallel execution.
 */

void _PD_net_pinit()
  {

#ifdef HAVE_THREADS
   int i;

   if (_PD_net_static == NULL)
      {_PD_net_static = NMAKE_N(FILE_STATIC, _PD_nthreads,
                                "_PD_NET_PINIT:_PD_net_static");

       for (i = 0; i < _PD_nthreads; i++)
           {_PD_net_static[i].pio_open_save     = NULL;
            _PD_net_static[i].pio_tell_save     = NULL;
            _PD_net_static[i].pio_read_save     = NULL;
            _PD_net_static[i].pio_write_save    = NULL;
            _PD_net_static[i].pio_setvbuf_save  = NULL;
            _PD_net_static[i].pio_close_save    = NULL;
            _PD_net_static[i].pio_seek_save     = NULL;
            _PD_net_static[i].pio_printf_save   = NULL;
            _PD_net_static[i].pio_puts_save     = NULL;
            _PD_net_static[i].pio_getc_save     = NULL;
            _PD_net_static[i].pio_ungetc_save   = NULL;
            _PD_net_static[i].pio_flush_save    = NULL;
            _PD_net_static[i].pio_gets_save     = NULL;
            _PD_net_static[i]._PN_host_chart    = NULL;
            _PD_net_static[i]._PN_host_std      = NULL;
            _PD_net_static[i]._PN_host_align    = NULL;};};
#endif

   return;}

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

