/*
 * PDASTS.C - test for the PDB I/O
 *
 * Source Version: 9.0
 * Software Release #92-0043
 *
 */

#include "cpyright.h"

#include "pdb.h"

#define DATFILE "nat"

#define N_DOUBLE 3
#define N_INT    5
#define N_CHAR  10
#define N_FLOAT  4

#define FLOAT_EQUAL(d1, d2)  (PD_float_equal(d1, d2, float_tolerance) == 0)
#define DOUBLE_EQUAL(d1, d2) (PD_float_equal(d1, d2, double_tolerance) == 0)

static short
 ss_w,
 ss_r,
 sa_w[N_INT],
 sa_r[N_INT];

static int
 is_w,
 is_r,
 ia_w[N_INT],
 ia_r[N_INT];

static char_8
 chrs_r[10],
 chrs_w[10];

static float
 fs_w,
 fs_r,
 fa1_w[N_FLOAT],
 fa1_r[N_FLOAT],
 fa2_w[N_FLOAT][N_DOUBLE],
 fa2_r[N_FLOAT][N_DOUBLE];

static double
 ds_w,
 ds_r,
 da_w[N_FLOAT],
 da_r[N_FLOAT];

static long
 ord_int8[]  = {1},
 ord_int24[] = {1, 3, 2},
 ord_int40[] = {1, 4, 2, 3, 5};

int
 test_1(),
 compare_test_1_data();

void
 main(),
 run_test(),
 test_target(),
 dump_test_symbol_table(),

 prep_test_1_data(),
 print_test_1_data(),
 write_test_1_data(),
 read_test_1_data();

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

/* MAIN - test the PDB Library system */

void main()
   {SIGNAL(SIGINT, SIG_DFL);

    run_test(test_1, 1, DATFILE);

    PRINT(STDOUT, "\n");

    exit(0);}

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

/* RUN_TEST - run a particular test through all targeting modes */

void run_test(test, n, host)
   PFInt test;
   int n;
   char *host;
   {char s[MAXLINE];
    double time;
    
    PRINT(STDOUT, "\nRunning test #%d\n", n);
    time = SC_wall_clock_time();

/* Cray target test */
    strcpy(s, "cray");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Sun4 target test */
    strcpy(s, "sun4");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Mips target test */
    strcpy(s, "mips");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Mips64 target test */
    strcpy(s, "mips64");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Alpha64 target test */
    strcpy(s, "alpha64");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Dos target test */
    strcpy(s, "dos");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Macintosh target test */
    strcpy(s, "mac");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Sun3 target test */
    strcpy(s, "sun3");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* Vax target test */
    strcpy(s, "vax");
    if (!(*test)(host, s, n))
       PRINT(STDOUT, "Test #%d %s failed\n", n, s);

/* native test */
    if (!(*test)(host, NULL, n))
       PRINT(STDOUT, "Test #%d native failed\n", n);

    time = SC_wall_clock_time() - time;
    PRINT(STDOUT, "Completed in %.2g seconds\n", time);

    return;}

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

/*                            TEST #1 ROUTINES                              */

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

/* TEST_1 - test the fundamental PDBLib functions
 *        - read and write data of all primitive types
 *        - tests can be targeted
 */

test_1(base, tgt, n)
   char *base, *tgt;
   int n;
   {PDBfile *strm;
    char datfile[MAXLINE], fname[MAXLINE];
    int err;
    FILE *fp;

/* target the file as asked */
    test_target(tgt, base, n, fname, datfile);

    fp = fopen(fname, "w");

/* create the named file */
    if ((strm = PD_create(datfile)) == NULL)
       {PRINT(fp, "Test couldn't create file %s\r\n", datfile);
        exit(1);};
    PRINT(fp, "File %s created\n", datfile);

    PD_defix(strm, "int8", 1, 1, NORMAL_ORDER);
    PD_defix(strm, "int40", 5, 4, REVERSE_ORDER);
    PD_defncv(strm, "char_8", 8, 1);

    PD_defloat(strm, "fp8", 1, 1, ord_int8, 2L, 5L, 5L, 6L, 0L, 0L, 1L);
    PD_defloat(strm, "fp24", 3, 4, ord_int24, 7L, 16L, 0L, 1L, 8L, 0L, 0x3F);

    PD_typedef(strm, "integer", "enum");

    prep_test_1_data();

/* write the test data */
    write_test_1_data(strm);

/* close the file */
    if (!PD_close(strm))
       {PRINT(fp, "Test couldn't close file %s\r\n", datfile);
        exit(1);};
    PRINT(fp, "File %s closed\n", datfile);

/* reopen the file */
    if ((strm = PD_open(datfile, "r")) == NULL)
       {PRINT(fp, "Test couldn't open file %s\r\n", datfile);
        exit(1);};
    PRINT(fp, "File %s opened\n", datfile);

/* dump the symbol table */
    dump_test_symbol_table(fp, strm->symtab, 1);

/* read the data from the file */
    read_test_1_data(strm);

/* compare the original data with that read in */
    err = compare_test_1_data(strm, fp);

/* close the file */
    if (!PD_close(strm))
       {PRINT(fp, "Test couldn't close file %s\r\n", datfile);
        exit(1);};
    PRINT(fp, "File %s closed\n", datfile);

/* print it out to STDOUT */
    print_test_1_data(fp);

    fclose(fp);
    if (err)
       remove(fname);

    return(err);}

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

/* PREP_TEST_1_DATA - prepare the test data */

void prep_test_1_data()
   {int i, k;

/* set scalars */
    ss_r = 0;
    is_r = 0;
    fs_r = 0.0;
    ds_r = 0.0;

    ss_w = -514;
    is_w =  10;
    fs_w =  3.14159;
    ds_w =  exp(1.0);

/* set short array */
    for (i = 0; i < N_INT; i++)
        {sa_w[i] = 2 - i;
         sa_r[i] = 0;};

/* set int array */
    for (i = 0; i < N_INT; i++)
        {ia_w[i] = i - 2;
         ia_r[i] = 0;};

/* set float array */
    for (i = 0; i < N_FLOAT; i++)
        for (k = 0; k < N_DOUBLE; k++)
            {fa2_w[i][k] = POW((double) (i+1), (double) (k+1));
             fa2_r[i][k] = 0.0;};

/* set double array */
    for (i = 0; i < N_FLOAT; i++)
        {da_w[i] = POW(ds_w, (double) (i+1));
         da_r[i] = 0.0;};

    strcpy(chrs_w[0], "foo");
    strcpy(chrs_w[1], "bar");
    strcpy(chrs_w[2], "baz");
    strcpy(chrs_w[3], "blat");
    strcpy(chrs_w[4], "tar fu");
    strcpy(chrs_w[5], "fu bar baz");
    memset(chrs_w[6], 0, 8);
    memset(chrs_w[7], 0, 8);
    memset(chrs_w[8], 0, 8);
    memset(chrs_w[9], 0, 8);

    for (i = 0; i < 10; i++)
        memset(chrs_r[i], 0, 8);

    return;}

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

/* WRITE_TEST_1_DATA - write out the data into the PDB file */

void write_test_1_data(strm)
   PDBfile *strm;
   {

    PD_write(strm, "chrs(10)", "char_8", chrs_w);

/* write scalars into the file */
    PD_write_as(strm, "ss", "short",   "int8",  &ss_w);
    PD_write_as(strm, "is", "enum",    "int40", &is_w);
    PD_write_as(strm, "fs", "float",   "fp8",   &fs_w);
    PD_write_as(strm, "ds", "double",  "fp24",  &ds_w);

/* write primitive arrays into the file */
    PD_write_as(strm, "sa(5)",    "short",   "int40", sa_w);
    PD_write_as(strm, "ia(5)",    "integer", "int40", ia_w);
    PD_write_as(strm, "fa2(4,3)", "float",   "fp8",  fa2_w);
    PD_write_as(strm, "da(4)",    "double",  "fp24", da_w);

    return;}

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

/* READ_TEST_1_DATA - read the test data from the file */

void read_test_1_data(strm)
   PDBfile *strm;
   {

    PD_read(strm, "chrs", chrs_r);

/* read the scalar data from the file */
    PD_read_as(strm, "ss", "short",   &ss_r);
    PD_read_as(strm, "is", "integer", &is_r);
    PD_read_as(strm, "fs", "float",   &fs_r);
    PD_read_as(strm, "ds", "double",  &ds_r);

/* read the primitive arrays from the file */
    PD_read_as(strm, "sa",  "short",   sa_r);
    PD_read_as(strm, "ia",  "integer", ia_r);
    PD_read_as(strm, "fa2", "float",   fa2_r);
    PD_read_as(strm, "da",  "double",  da_r);

    return;}

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

/* PRINT_TEST_1_DATA - print it out to STDOUT */

void print_test_1_data(fp)
   FILE *fp;
   {int i, k;

/* print scalars */
    PRINT(fp, "short scalar:   ss = %d\n", ss_r);
    PRINT(fp, "integer scalar: is = %d\n", is_r);
    PRINT(fp, "float scalar:   fs = %14.6e\n", fs_r);
    PRINT(fp, "double scalar:  ds = %14.6e\n", ds_r);

    PRINT(fp, "\n");

/* print short array */
    PRINT(fp, "short array:\n");
    for (i = 0; i < N_INT; i++)
        PRINT(fp, "  sa[%d] = %d\n", i, sa_r[i]);

/* print int array */
    PRINT(fp, "integer array:\n");
    for (i = 0; i < N_INT; i++)
        PRINT(fp, "  ia[%d] = %d\n", i, ia_r[i]);

/* print float array */
    PRINT(fp, "float array:\n");
    for (i = 0; i < N_FLOAT; i++)
        for (k = 0; k < N_DOUBLE; k++)
            PRINT(fp, "  fa2[%d][%d] = %14.6e\n", i, k, fa2_r[i][k]);

/* print double array */
    PRINT(fp, "double array:\n");
    for (i = 0; i < N_FLOAT; i++)
        PRINT(fp, "  da[%d] = %14.6e\n", i, da_r[i]);

    PRINT(fp, "\n");

    return;}

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

/* COMPARE_TEST_1_DATA - compare the test data */

compare_test_1_data(strm, fp)
   PDBfile *strm;
   FILE *fp;
   {int i, k, err, err_tot;
    int float_nm, double_nm;
    double float_tolerance, double_tolerance;

    float_nm  = min(strm->std->float_format[2],
                    strm->host_std->float_format[2]);
    double_nm = min(strm->std->double_format[2],
                    strm->host_std->double_format[2]);

/* pad the absolute tolerance */
    float_tolerance  = POW(2.0, -((double) float_nm));
    double_tolerance = POW(2.0, -((double) double_nm));
    err_tot = TRUE;

/* compare scalars */
    err  = TRUE;
    err &= (ss_r == ss_w);
    err &= (is_r == is_w);
    err &= FLOAT_EQUAL(fs_r, fs_w);
    err &= DOUBLE_EQUAL(ds_r, ds_w);

    if (err)
       PRINT(fp, "Scalars compare\n");
    else
       PRINT(fp, "Scalars differ\n");
    err_tot &= err;

/* compare char_8 array */
    err = TRUE;
    for (i = 0; i < 10; i++)
        err &= (strncmp(chrs_w[i], chrs_r[i], 8) == 0);

    if (err)
       PRINT(fp, "Char_8 arrays compare\n");
    else
       PRINT(fp, "Char_8 arrays differ\n");
    err_tot &= err;

    err = TRUE;

/* compare short array */
    for (i = 0; i < N_INT; i++)
        err &= (sa_r[i] == sa_w[i]);

/* compare int array */
    for (i = 0; i < N_INT; i++)
        err &= (ia_r[i] == ia_w[i]);

/* compare float array */
    for (i = 0; i < N_FLOAT; i++)
        for (k = 0; k < N_DOUBLE; k++)
            {err &= FLOAT_EQUAL(fa2_r[i][k], fa2_w[i][k]);};

/* compare double array */
    for (i = 0; i < N_FLOAT; i++)
        err &= DOUBLE_EQUAL(da_r[i], da_w[i]);

    if (err)
       PRINT(fp, "Arrays compare\n");
    else
       PRINT(fp, "Arrays differ\n");
    err_tot &= err;

    return(err_tot);}

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

/*                         GENERAL PURPOSE ROUTINES                         */

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

/* TEST_TARGET - set up the target for the data file */

void test_target(tgt, base, n, fname, datfile)
   char *tgt, *base;
   int n;
   char *fname, *datfile;
   {if (tgt != NULL)
       {if (strcmp(tgt, "dos") == 0)
           PD_target(&INTELA_STD, &INTELA_ALIGNMENT);
        else if (strcmp(tgt, "rs6000") == 0)
           PD_target(&IEEEA_STD, &MIPS_ALIGNMENT);
        else if (strcmp(tgt, "cray") == 0)
           PD_target(&CRAY_STD, &UNICOS_ALIGNMENT);
        else if (strcmp(tgt, "vax") == 0)
           PD_target(&VAX_STD, &DEF_ALIGNMENT);
        else if (strcmp(tgt, "mips") == 0)
           PD_target(&IEEEA_STD, &MIPS_ALIGNMENT);
        else if (strcmp(tgt, "mips64") == 0)
           PD_target(&IEEED_STD, &MIPS64_ALIGNMENT);
        else if (strcmp(tgt, "alpha64") == 0)
           PD_target(&IEEEE_STD, &ALPHA64_ALIGNMENT);
        else if (strcmp(tgt, "sun3") == 0)
           PD_target(&IEEEA_STD, &M68000_ALIGNMENT);
        else if (strcmp(tgt, "sun4") == 0)
           PD_target(&IEEEA_STD, &SPARC_ALIGNMENT);
        else if (strcmp(tgt, "mac") == 0)
           PD_target(&IEEEB_STD, &M68000_ALIGNMENT);
        sprintf(fname, "%s-%s.rs%d", base, tgt, n);
        sprintf(datfile, "%s-%s.db%d", base, tgt, n);}
    else
       {sprintf(fname, "%s-nat.rs%d", base, n);
        sprintf(datfile, "%s-nat.db%d", base, n);};

    return;}

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

/* DUMP_TEST_SYMBOL_TABLE - dump the symbol table */

void dump_test_symbol_table(fp, tab, n)
   FILE *fp;
   HASHTAB *tab;
   int n;
   {int i;
    char **names;

    PRINT(fp, "\nTest %d Symbol table:\n", n);

    names = SC_hash_dump(tab, NULL);
    for (i = 0; i < tab->nelements; i++)
        PRINT(fp, "%s\n", names[i]);

    PRINT(fp, "\n");

    return;}

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

/* PD_FLOAT_EQUAL - compare two floating point numbers
 *                - which have different precision
 */

PD_float_equal(d1, d2, tol)
   double d1, d2, tol;
   {double del;

    if (d1 == d2)
       return(0);

    del = (d1 - d2)/(ABS(d1) + ABS(d2) + SMALL);
    if (del < -tol)
       return(-1);
    else if (tol < del)
       return(1);
    else
       return(0);}

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