#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <memory.h>

#define GRIB 0x47524942
#define BUFR 0x42554652
#define BUDG 0x42554447
#define DIAG 0x44494147
#define TIDE 0x54494445

#ifdef FORTRAN_NO_UNDERSCORE
#define DECOPS2  decops2
#else
#define DECOPS2  decops2_
#endif

#define SIZE 20000
#define BLOCK_1_LEN 18
#ifdef CRAY
#define BITS_PER_WORD 64
#else
#define BITS_PER_WORD 32
#endif
 
void decode_data( char * type, char * buffer, long * prodsize);

static long file_read(char * buff, long leng, void * file)
/*
    buff = buffer to fill,
    leng = size of buff in bytes,
    file = FILE *.
 
    Returns the number of bytes read.
    On EOF, returns negative value for number of bytes read .
*/
{
long nbytes;
 
    nbytes = (long) fread( buff, 1, leng, (FILE *) file);
 
/* If EOF, return negative number of bytes read */
    if ( feof((FILE *) file ) )
    {
        clearerr( (FILE *) file );
        return (-nbytes);
    }
 
    return nbytes;
}

#ifdef __uxp__
MAIN__( int argc, char ** argv)
#else
main( int argc, char ** argv)
#endif
{
FILE * fin;
long status, offset = 0;
long prodsize;
char * buffer;
long startpos;
char * p;
char type[5];
long ident = 0;
int i;

    if ( argc < 2 )
    {
        printf("usage: pseudoprt filename [offset]\n");
        exit (1);
    }

/*  Open the file. */
    fin = fopen( argv[1], "r");
    if ( fin == NULL )
    {
        perror(" fopen failed");
        exit(1);
    }

/*  If a byte offset given, position the file. */
    if ( argc >2 )
    {
        for ( p = argv[2] ; *p; p++ )
            if ( ! isdigit( *p) )
            {
                printf("Bad offset given in second argument = %s\n", argv[2]);
                exit(1);
            }
        offset = atol( argv[2] );
    }

    status = fseek( fin, offset, 0L );
    if (status != 0 )
    {
        perror("fseek failed");
        exit(1);
    }
        
/*  read the next product. */
    status = readnext( NULL, &prodsize, file_read, fin); 
    if ( status == -3 )
    {
        status = fseek( fin, -prodsize, 1L );
        if (status != 0 )
        {
            perror("fseek after readnext failed");
            exit(1);
        }

        startpos = ftell( fin );
        buffer = (char *) malloc( prodsize );
        if ( buffer == NULL )
        {
            perror("malloc error");
            exit(1);
        }

        status = readnext( buffer, &prodsize, file_read, fin);
        if ( status != 0 )
        {
            printf("readnext failed!!\n");
            exit(1);
        }

/*      Extract the product type, and handle accordingly.
        GRIB should not occur here!                       */

        memcpy( type, buffer, 4);
        type[4] = '\0';

        for ( i = 0; i < 4; i++ )
            ident = ( (ident << 8) + *(type+i) ) & 0xFFFFFFFF;

        switch ( ident )
        {
            case GRIB:
                printf("GRIB found\n");
                break;

            case BUDG:
                decode_data( type, buffer, &prodsize);
                break;

            case TIDE:
                decode_data( type, buffer, &prodsize);
                break;

            case DIAG:
                decode_data( type, buffer, &prodsize);
                break;

            case BUFR:
                printf("BUFR found\n");
                break;

            default:
                printf("No recognized type found: type = %s\n", type);
                break;
        }

    }

    free( buffer );
    fclose( fin );

}

void decode_data( char * type, char * buffer, long * bufsize)
{
char chdata[SIZE];
float fpdata[SIZE];
int indata[SIZE];
int lgdata[SIZE];
int ilench = SIZE, ilenfp = SIZE, ilenin = SIZE, ilenlg = SIZE;
int nbyte = sizeof(int);
int ib1par[BLOCK_1_LEN];
int nbit = BITS_PER_WORD;
int jlench, jlenfp,jlenin,jlenlg, irserv, iword, ierr;
int i, num_per_line, num_per_line_m1;

     DECOPS2( type, chdata, &ilench, fpdata, &ilenfp, indata, &ilenin,
             &nbyte, lgdata, &ilenlg, ib1par, buffer, bufsize,
             &jlench, &jlenfp, &jlenin, &jlenlg, &irserv, &nbit, &iword,
             &ierr);

     if ( ierr != 0 )
     {
         printf("DECOPS2 returned status code %d\n", ierr);
         exit(1);
     }

     printf("\n");
     printf("Product type is %s\n", type);
     printf("--------------------\n\n");

     printf("Number of words decoded = %d\n\n", iword);

     printf("Product definition block information.\n");
     printf("-------------------------------------\n\n");

     printf("Orginating centre identifier        = %d\n", ib1par[0]);
     printf("Model identification                = %d\n", ib1par[1]);
     printf("Grid definition                     = %d\n", ib1par[2]);
     printf("Flag (code table 1)                 = %x\n", ib1par[3]);
     printf("Parameter identifier (code table 2) = %d\n", ib1par[4]);
     printf("Type of level (code table 3)        = %d\n", ib1par[5]);
     printf("Level 1 (code table 3)              = %d\n", ib1par[6]);
     printf("Level 2 (code table 3)              = %d\n", ib1par[7]);
     printf("Year of data                        = %d\n", ib1par[8]);
     printf("Month of data                       = %d\n", ib1par[9]);
     printf("Day of data                         = %d\n", ib1par[10]);
     printf("Hour of data                        = %d\n", ib1par[11]);
     printf("Minute of data                      = %d\n", ib1par[12]);
     printf("Time unit (code table 4)            = %d\n", ib1par[13]);
     printf("Time range one                      = %d\n", ib1par[14]);
     printf("Time range two                      = %d\n", ib1par[15]);
     printf("Time range flag (code table 5)      = %x\n", ib1par[16]);
     printf("Number averaged                     = %d\n", ib1par[17]);

     printf("\n\n");
     printf("Binary data block information.\n");
     printf("------------------------------\n");

     printf("\n");

     printf("Character data.\n");
     printf("---------------\n");
     num_per_line = 40;
     num_per_line_m1 = num_per_line-1;
     if ( jlench < 0 ) printf("Missing data code.\n\n");
     if ( jlench == 0 ) printf("None.\n");
     if ( jlench > 0 )
     {
         printf("Number of values = %d\n\n", jlench);
         for ( i = 0; i < jlench; i++ )
         {
             printf("%c", chdata[i]);
             if( (i%num_per_line) == num_per_line_m1 ) printf("\n");
         }
     }

     printf("\n\n");

     printf("Floating point data.\n");
     printf("--------------------\n");
     num_per_line = 5;
     num_per_line_m1 = num_per_line-1;
     if ( jlenfp < 0 ) printf("Missing data code.\n\n");
     if ( jlenfp == 0 ) printf("None.\n");
     if ( jlenfp > 0 )
     {
         printf("Number of values = %d\n\n", jlenfp);
         for ( i = 0; i < jlenfp; i++ )
         {
             printf("%30.15f ", fpdata[i]);
             if( (i%num_per_line) == num_per_line_m1 ) printf("\n");
         }
     }

     printf("\n\n");

     printf("Integer data.\n");
     printf("-------------\n");
     num_per_line = 8;
     num_per_line_m1 = num_per_line-1;
     if ( jlenin < 0 ) printf("Missing data code.\n\n");
     if ( jlenin == 0 ) printf("None.\n");
     if ( jlenin > 0 )
     {
         printf("Number of values = %d\n\n", jlenin);
         for ( i = 0; i < jlenin; i++ )
         {
             printf("%9i ", indata[i]);
             if( (i%num_per_line) == num_per_line_m1 ) printf("\n");
         }
     }

     printf("\n\n");

     printf("Logical data.\n");
     printf("-------------\n");
     num_per_line = 40;
     num_per_line_m1 = num_per_line-1;
     if ( jlenlg < 0 ) printf("Missing data code.\n\n");
     if ( jlenlg == 0 ) printf("None.\n");
     if ( jlenlg > 0 )
     {
         printf("Number of values = %d\n\n", jlenlg);
         for ( i = 0; i < jlenlg; i++ )
         {
             printf("%1i ", lgdata[i]);
             if( (i%num_per_line) == num_per_line_m1 ) printf("\n");
         }
     }

}
