/*******************************************************************
 * Copyright (c) 1975-94 Regents of the University of California.  *
 * All Rights Reserved.                                            *
 *                                                                 *
 * Redistribution and use in source and binary forms are permitted *
 * provided that the above copyright notice and this paragraph are *
 * duplicated in all such forms and that any documentation,        *
 * advertising materials, and other materials related to such      *
 * distribution and use acknowledge that the software was developed*
 * by the University of California, Los Angeles. The name of the   *
 * University may not be used to endorse or promote products       *
 * derived from this software without specific prior written       *
 * permission. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY   *
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT  LIMITATION,  *
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A     *
 *PARTICULAR PURPOSE.                                              *
 ******************************************************************/ 
/*BEGIN DOCUMENTATION*********************************************+/
/* FILE            |   ff_igpp.c                                  */
/* Utility         |Utilities for UCLA-IGPP Flatfiles.            */
/*                 cFlatfiles are a pair of files:                */
/*                 c *.ffh - flatfile header, an ascii file       */
/*                 c         datafile parameters and descriptions */
/*                 c *.ffd - flatfile datafile, binary datafile   */
/* PrincipalInvest |Christopher Russell,ctrussell@igpp.ucla.edu,  */
/*                               (310)825-3188                    */
/* Creator         |Harry Hebert 1975-1994                        */
/* Programmer      |Louise Lee,leel@igpp.ucla.edu,(310)206-9955   */
/******************************************************************/
/*VERSION 2.0 *****************************************************/
/* L.Lee   12/16/99N Vax support removed                          */
/* L.Lee   12/16/99N Begin implementation for PC                  */
/* L.Lee   12/16/99N FF_IGPP Dirty Trick: even though the signature list may  */
/*                 C require a pointer to a header struct, a pointer to a data*/
/*                 C struct can be used instead.  Both struct contains the    */
/*                 C field, type, to indicate whether its a header or a data  */
/*                 C struct, and pointers to itself and the corresponding     */
/*                 C header/data struct respectively. Routines check whether  */
/*                 C the struct is the proper type, if not replace the pointer*/
/*                 C to the correct one. Which means that the *ffd,*ffh must  */
/*                 C be defined. Possible pointer could be corrupted.         */
/* L.Lee   12/16/99N FF_IGPP Dirty Trick Fix: replace structs to a class      */
/*                 N the base class would be flatfilestruct and the ffd,ffh   */
/*                 N be inherited classes                                     */
/* L.Lee   02/17/00N Begin a "clean version" remove obsolete code             */
/*                   Delete all commented code                                */
/* L.Lee   02/17/00N Implement EPOCH type to ff utilities                     */
/******************************************************************************/
/* L.Lee   12/16/99U Defined signature list for routines in ff_igpp.h and     */
/*                 C typed calls such that it will match the signature list   */
/*                 C calls are ff_setrows and the ff_hput/get routines        */
/******************************************************************************/
/* L.Lee   11/30/00N ff_hput/ff_hget : increase unit string field descriptor  */
/*                 C from 10 characters to 24                                 */
/******************************************************************************/
/* L.Lee   08/06/03N Add support for 3 time system: Julian Day Atomic time    */
/******************************************************************************/
/*
 * C version of IGPP flat file library.  The master source code file
 * for this library of routines is kept on the IGPP PLAnet Unix systems.
 * Changes to this code should me made there, and then the code
 * tranfered to other systems.
 */

#ifndef lint
static char sccsid[]="%W% %G%";
#endif

#ifndef MACOS
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <string.h>

#include <ctype.h>
#include <math.h>

#define PC  /* Added, jw, Dec 2003 */
#ifndef PC
#include <strings.h>
#include <unistd.h>	    /* needed for lockf cmd */
#include <sys/file.h>	/* needed for access & F_OK */
#include <sys/param.h>	/* needed for MAXPATHLEN */
#endif
#define MAXFF(x,y) ( (x) > (y) ? (x) : (y) )
#define MINFF(x,y) ( (x) < (y) ? (x) : (y) )
#ifdef PC
#include <process.h>
#include <stdlib.h>
#include <io.h>
#define F_OK 0
#define MAXPATHLEN 256
#endif

#define FF_LIB
#include "time_igpp.h"   /* Changed <> to "", jw, Dec 2003 */
#include "ff_igpp.h"

#define INTEL  /* Added, jw, Dec 2003 */
#ifdef INTEL
void FFSwapRecords(char *buffer,int nchar);
#endif
#define FF_WITHPATH 1
#define FF_WITHOUTPATH 0
#define NKEY 6
#define NEPOCH 4

static char *keywords[NKEY]={"FIRST TIME","LAST TIME","OWNER",
	                           "MISSING DATA FLAG","AVERAGE INTERVAL",
                             "ORBIT NUMBER(S)"};
static int lenkey[NKEY]={10,9,5,17,16,15};
/* Support 3 time systems:
     cline time                   : 1966 Jan 01 00:00:00.000
     Modified Juilian Atomic time : 2000 Jan 01 00:00:00.000
              Juilian Atomic time : 2000 Jan 01 12:00:00.000
*/
/* leel 2003 NOV support for 1958 epoch */
static char *EPOCHNAMES[NEPOCH]={"Y1966","Y2000","J2000","Y1958"};
static int ff_silent = 0;
static int ff_oldstyle= 0;
#ifdef USEIT
/* leel 05/17/00 offset = 1 if EPOCH exists 0 if old format */
static int eoffset=0; 
#endif
/* for variable unit length */
#define OLDUNITLEN 10
int  ff_col_format=OLDUNITLEN;
static char format1[]="%3c %-10s%-";
static char format2[]="s%-26s%-22s";
static char formatA[]="%3.3d %-10.10s%-";
static char formatB[]="s%-26.26s%-4.4s  % 4d %-";
static char formata[]="%3d%*c%10c%";
static char formatb[]="c%26c%4s %d";
static char format0[80];
static int oldUnitLen =OLDUNITLEN; /* # chars for unit descriptor field */
#define NSTARTCOLDESC 6    /* line the Column desciptors begin in header file (0 is first line)*/

/*
  ff_minid and ff_maxid are used in an attempt to screen bad 
  struct pointers which can be passed by the programmer to
  these ff routines.  If one tries to access an address referenced
  by a bad pointer one gets a "segmentation fault".  If we first
  check to see if the id falls within the range of ids which have
  been allocated, then we can prevent some of these faults, and
  provide a EBADF error message - bad file number.
  Initialize ff_minid with a very high address - this may not be
  transportable to systems which don't allow integer comparisons of
  addresses.
*/
static void *ff_minid=(void *)2147483650UL,*ff_maxid=NULL;

/* leel 08/06/03 NOTE I've done this somewhere else(LINUX) */
#if (MACOS )
extern const char * const sys_errlist[];
#endif
#if (SUN)
extern char *sys_errlist[];
#endif

extern int errno;
void ff_routineerror();
char *strsrch(char *string1,char *string2);
int GetUnitLength(FF_HID *id);

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        | ff_open - Open flat file pair                            */
/* USAGE           | FF_ID *ff_open (char *fname,FF_O_PARAM *o_parms);        */
/* RETURN          | FF_ID * - pointer to flatfile structure,NULL if failed   */
/* PARAMETER       I char *fname - flatfile name w/o extensions               */
/* PARAMETER       T FF_O_PARAM *o_parms - flatfile parameter struct          */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/* UPDATES         | Apr 18,91Now fills datafields structure on existing files*/
/*END DOCUMENTATION************************************************************/
FF_ID *ff_open(char *fname,FF_O_PARAM *o_parms){
  extern int ff_silent;
  char *p,string[32],fopen_type[4];
  FF_ID *id;
  FILE *ffh;
  int ff_buildname();
  int isize;
  int n,l,t,verify_ex,fexist,status,recl,ncols,nbufs,overwrite,lock,loc;
  long nrows;
  enum EPOCH epoch=Y1966; /* default to Y1966 cline time */
  char buffer[73];
  char key[73];

  long fpos;
  char k;
  if ((id = (FF_ID *)malloc(sizeof (FF_ID))) == NULL) goto memerr;
  id->type = FF_MAINID;

/* Keep track of min and max pointers, to detect bad file ids */
  if (id < (FF_ID *)ff_minid) ff_minid = (void *)id;
  if (id > (FF_ID *)ff_maxid) ff_maxid = (void *)id;

  id->ffd = NULL;
  if ((id->ffh = (FF_HID *)malloc(sizeof (struct ff_header))) == NULL) goto memerr;
  if (id->ffh < (FF_HID *)ff_minid) ff_minid = (void *)id->ffh;
  if (id->ffh > (FF_HID *)ff_maxid) ff_maxid = (void *)id->ffh;

  id->ffh->fp = NULL;
  id->ffh->error = 0;
  id->ffh->type = FF_HEADER;
  id->ffh->eoffset = 7;
  id->ffh->fmunit=OLDUNITLEN;

/* Header file name, with path. */
  if ((id->ffh->name = (char *)malloc(MAXPATHLEN)) == NULL) goto memerr;
  n = ff_buildname(fname,id->ffh->name,FF_HEADER,FF_WITHPATH);
  id->ffh->name = (char *)realloc(id->ffh->name,n+1);

  verify_ex = 0;
  /* epoch is not defined default to current settings */
  switch(o_parms->epoch){
    case(Y1966):case(Y2000):case(J2000): case(Y1958):break;
    default    :printf("ff_open WARNING : ");
                printf("epoch %d is undefined : set to ",o_parms->epoch);
                epoch=o_parms->epoch=WhichEpoch();
                switch(epoch){
                  case(Y1958): printf("Y1958\n");break;
                  case(Y1966): printf("Y1966\n");break;
                  case(Y2000): printf("Y2000\n");break;
                  case(J2000): printf("J2000\n");break;
                }
  }
  status = (o_parms->status & ~FF_LOCK);
  lock = status != o_parms->status;
  switch (status) {
    case FF_CREATE | FF_WRITE:
    case FF_WRITE:
    case FF_CREATE:
      status = FF_CREATE | FF_WRITE;
      strcpy(fopen_type,"w");
      verify_ex = 1;
      break;
    case FF_CREATE | FF_READ | FF_WRITE:
      strcpy(fopen_type,"w+");
      verify_ex = 1;
      break;
    case FF_EXIST | FF_READ:
    case FF_READ:
    case FF_EXIST:
      status = FF_EXIST | FF_READ;
      strcpy(fopen_type,"r");	/* existence is verified by fopen() */
      break;
    case FF_EXIST | FF_READ | FF_WRITE:
    case FF_EXIST | FF_WRITE:
    case FF_READ | FF_WRITE:
      status = FF_EXIST | FF_READ | FF_WRITE;
      strcpy(fopen_type,"r+");	/* existence is verified by fopen() */
      break;
    case FF_EXIST | FF_CREATE | FF_WRITE:	/* Create if doesn't exist */
    case FF_EXIST | FF_CREATE:		/* without verifying ex'nce */
      status = FF_EXIST | FF_CREATE | FF_WRITE;
      strcpy(fopen_type,"w");
      break;
    case FF_EXIST | FF_CREATE | FF_READ | FF_WRITE:
      strcpy(fopen_type,"w");
      break;
    default:
      if (ff_stderr != NULL)
	fprintf(ff_stderr,"Flat file error: %s : Invalid open options\n",
	id->ffh->name);
      errno = EACCES; goto herrorret;
  }
#ifndef INTEL
/* access returns 0 if file exists, else -1 */
  overwrite = 0;
  if (verify_ex) {
    fexist = !access(id->ffh->name,F_OK) * FF_EXIST;
    if (fexist != (FF_EXIST & status)) {
      if (fexist) {
/*
	if (isatty(0) && isatty(fileno(ff_stdout))) {
	  fprintf(ff_stdout,
		"\07%s: file exists, do you wish to overwrite it? (y/n)",
	    id->ffh->name);
	  string[0] = '\0';
	  gets(string);
	  overwrite = strchr(string,'y') != NULL || strchr(string,'Y') != NULL; 
	}
*/
	if (!overwrite) {
	  errno = EEXIST;
	  goto herrorret;
	}
      }
      else {
	errno = ENOENT;
	goto herrorret;
      }
    }
  }
#endif

  id->ffh->fp = fopen (id->ffh->name,fopen_type);
  if (id->ffh->fp == NULL) goto herrorret;
  ffh = id->ffh->fp;

#ifndef PC
  if (lock) if (lockf(fileno(ffh),F_TLOCK,0) == -1) goto herrorret;
#endif
  
  if (ff_stdout != NULL && !ff_silent) fprintf (ff_stdout,"C1Opened: %s\n",id->ffh->name);

/* Record length is needed here for VMS systems */
  if ( status & FF_CREATE ) {
    recl = o_parms->recl;
    ncols = o_parms->ncols;
    nrows = o_parms->nrows;
    epoch = o_parms->epoch;
  /* epoch is not defined default to current settings */
    switch(o_parms->epoch){
      case(Y1966):
                  break;
      case(Y2000): SetEpoch2AT();
                  break;
      case(J2000): SetEpoch2JT();
                  break;
      case(Y1958): SetEpoch2SC();
                  break;
      default    :printf("ff_open WARNING : ");
                  printf("for %s  ",fname);
                  printf("epoch %d is undefined : set to ",o_parms->epoch);
                  epoch=o_parms->epoch=WhichEpoch();
                  switch(epoch) {
                    case(Y1966): printf("CLINE TIME\n");break;
                    case(Y2000): printf("Y2000\n");break;
                    case(J2000): printf("J2000\n");break;
                    case(Y1958): printf("Y1958\n");break;
                  }/* end switch epoch */
    }
  } /* end status & FF_CREATE */
  else {
    id->ffh->eoffset=0;
    if (fseek(ffh,2*72L,0)) goto herrorret;
    if (fscanf(ffh,"RECL  =%d",&recl)!=1) goto hreaderror;
    if (fscanf(ffh," NCOLS =%d",&ncols)!=1) goto hreaderror;
    if (fscanf(ffh," NROWS =%d",&nrows)!=1) goto hreaderror;
    fpos=ftell(ffh);
    fscanf(ffh,"%s %s %s ",key,buffer,buffer);
    if(strcmp(key,"OPSYS")==0){
        k=toupper(buffer[0]);
        id->opsys= ((k=='S')?SUNOPS:((k=='H')?UNIXOPS:PCOPS));
        fpos=ftell(ffh);
        fscanf(ffh,"%s %s %s ",key,buffer,buffer);
        if(strcmp(key,"EPOCH")==0){
           switch(buffer[0]){
             case('Y'):if(buffer[1]=='1')
                       epoch=(buffer[3]=='6')?Y1966:Y1958;
                       else
                       epoch= Y2000;
                       break;
             case('J'):epoch=J2000;
                       break;
           } /* end switch */
           if(epoch==Y2000)SetEpoch2AT();
           if(epoch==J2000)SetEpoch2JT();
           if(epoch==Y1958)SetEpoch2SC();
           id->ffh->eoffset=1;
        } /* end if */
    } /* end strcmp */
    else if(strcmp(key,"EPOCH")==0){
        id->ffh->eoffset=1;
        switch(buffer[0]){
          case('Y'):if(buffer[1]=='1')
                      epoch=(buffer[3]=='6')?Y1966:Y1958;
                    else
                      epoch= Y2000;
                    break;
          case('J'):epoch=J2000;
                    break;
        } /* end switch */
        if(epoch==Y1958)SetEpoch2SC();
        if(epoch==Y2000)SetEpoch2AT();
        if(epoch==J2000)SetEpoch2JT();
    }
    else 
    { printf(" not last %s\n",buffer);fseek(ffh,fpos,SEEK_SET);
     }
     o_parms->epoch=epoch; /* set to correct epoch */
  }
  switch(epoch){
    case(Y1958):SetEpoch2SC();break;
    case(Y1966):SetEpoch2CT();break;
    case(Y2000):SetEpoch2AT();break;
    case(J2000):SetEpoch2JT();break;
  } 
  if(o_parms->status&FF_EXIST||o_parms->status&FF_READ){
     id->ffh->fmunit=GetUnitLength(id->ffh);
}

  if ((id->ffd = (FF_DID *)malloc(sizeof (struct ff_data))) == NULL) goto memerr;
  if (id->ffd < (FF_DID *)ff_minid) ff_minid = (void *)id->ffd;
  if (id->ffd > (FF_DID *)ff_maxid) ff_maxid = (void *)id->ffd;
  id->ffd->fp = NULL;
  id->ffd->error = 0;
  id->ffd->type = FF_DATA;
  id->ffd->name = NULL;
  id->ffd->df = NULL;
  id->ffd->epoch = epoch;

  if ((id->ffd->name = (char *)malloc(MAXPATHLEN)) == NULL) goto memerr;
  n = ff_buildname(fname,id->ffd->name,FF_DATA,FF_WITHPATH);
  id->ffd->name = (char *)realloc(id->ffd->name,n+1);

#ifndef PC
/* If .ffh doesn't exist but .ffd does, this will generate an error */
  if (verify_ex && !overwrite) {
    fexist = !access(id->ffd->name,F_OK) * FF_EXIST;
    if (fexist != (FF_EXIST & status)) {
      if (fexist && !overwrite) {
         errno = EEXIST;
         goto derrorret;
      }
      else {
        errno = ENOENT;
        goto derrorret;;
      }
    }
  }
#endif

  isize=strlen(fopen_type);
  fopen_type[isize]='b';
  fopen_type[isize+1]='\0';
  id->ffd->fp = fopen (id->ffd->name,fopen_type);
  if (id->ffd->fp == NULL) goto derrorret;

  nbufs = MAXFF(o_parms->nbufs,1);
  nbufs = MINFF(nbufs,20);
#ifndef PC
  if (nbufs>1)
      if (setvbuf(id->ffd->fp,NULL,_IOFBF,nbufs*BUFSIZ) != 0) goto derrorret;
  if (lock) if (lockf(fileno(id->ffd->fp),F_TLOCK,0) == -1) goto derrorret;
#endif
  
  if (ff_stdout != NULL && !ff_silent) fprintf (ff_stdout,"C0Opened: %s  Nbuf:%d\n",id->ffd->name,nbufs);

  id->status = status;
  id->ffd->recl = recl;
  id->ffd->ncols = ncols;
  id->ffd->df = NULL;

  if ( status & FF_CREATE ) {
    id->ffd->nrows = 0;
    id->ffd->size = 0;

/* Write "DATA  = " record. */
    p = strrchr(id->ffd->name,'/');
    if (p++ == NULL) p = id->ffd->name;
    if (fprintf (ffh,"DATA  = %-64.64s",p)==EOF) goto herrorret;

/* Write "CDATE = " record. */
    t_con_c (t_now(),string);
    if (fprintf(ffh,"CDATE = %-64.24s",string)==EOF) goto herrorret;
    if (fprintf(ffh,"RECL  =%6d%-59c",recl,' ')==EOF) goto herrorret;
    if (fprintf(ffh,"NCOLS =%6d%-59c",ncols,' ')==EOF) goto herrorret;
    if (fprintf(ffh,"NROWS =%11d%-54c",0,' ')==EOF) goto herrorret;

#if (sun || solaris || SUN)
    if (fprintf (ffh,FF_FORMAT,"OPSYS = SUN/UNIX")==EOF) goto herrorret;
#endif
#ifdef hpux
    if (fprintf (ffh,FF_FORMAT,"OPSYS = HP/UNIX")==EOF) goto herrorret;
#endif
#ifdef PC
    if (fprintf (ffh,FF_FORMAT,"OPSYS = WINDOWS")==EOF) goto herrorret;
#endif
#ifdef LINUX
    if (fprintf (ffh,FF_FORMAT,"OPSYS = LINUX")==EOF) goto herrorret;
#endif
#ifdef MACOS
    if (fprintf (ffh,FF_FORMAT,"OPSYS = MACOS")==EOF) goto herrorret;
#endif
    if(!ff_oldstyle){
      switch(o_parms->epoch){
        case(Y1958): sprintf(buffer,"EPOCH = %s","Y1958");
                     SetEpoch2SC();
                     break;
        case(Y1966): sprintf(buffer,"EPOCH = %s","Y1966");
                     SetEpoch2CT();
                     break;
        case(Y2000): sprintf(buffer,"EPOCH = %s","Y2000");
                     SetEpoch2AT();
                     break;
        case(J2000): sprintf(buffer,"EPOCH = %s","J2000");
                     SetEpoch2JT();
                     break;
      } /* end switch */
      id->ffh->eoffset = 1;
      if (fprintf (ffh,FF_FORMAT,buffer)==EOF) goto herrorret;
    }
    else
      id->ffh->eoffset = 0;
/* leel 12/05/00 variable unit format */
    sprintf(format0,"%s%-d%s\0",format1,ff_col_format,format2);
    id->ffh->fmunit=ff_col_format;
    if (fprintf (ffh,format0,'#',"NAME","UNITS","SOURCE","TYPE  LOC")==EOF) goto herrorret;
    fflush(ffh);
  }
  else {
    o_parms->recl = recl;
    o_parms->ncols = ncols;
    o_parms->nrows = nrows;
    o_parms->epoch = epoch;

    id->ffd->nrows = nrows;
    id->ffd->size  = nrows * recl;
    id->ffd->epoch = epoch;
/*
    if(epoch==Y2000)SetEpoch2AT();
    else SetEpoch2CT();
*/

/* Scan header for data types and sizes */
    if ((id->ffd->df=(struct ff_datafields *)malloc(sizeof(struct ff_datafields) * ncols))==NULL)
	  goto memerr;
    for (n=0,loc=0; n<ncols; n++) {

/* Position to beginning of record for VMS's sake */
/* leel 12/18/00 offset */
      if (fseek(ffh,(n+7+id->ffh->eoffset)*72L,0)) goto herrorret;
      if (fscanf(ffh,"%*48c%4s",string)!=1) {
	if (!n) { t = TIME66;	l=8; }
	else { t = FLOAT;	l=4; }
      }
      for (p=string; *p != '\0'; p++) if (islower(*p)) *p = toupper(*p);
      switch (string[0]) {
      case 'T': t = TIME66;	l = 8; break;
      case 'D': t = DOUBLE;	l = 8; break;
      case 'B': t = BYTE;	l = 1; break;
      case 'L': t = LONG;	l = 4; break;
      case 'S': t = SHORT;	l = 2; break;
      case 'R':
	t = FLOAT;	l = 4;
	if (!strcmp(string,"R*8")) {
	  if (!n) t = TIME66;
	  else t = DOUBLE;
	  l = 8;
	}
	break;
      case 'I':
	t = LONG;	l = 4;
	if (!strchr(string,'2')) { l = 2; t = SHORT; }
	break;
      case 'A':
	t = CHAR;
	for (p = string+1; *p != '\0' && !isdigit(*p); p++) ;
	l = atoi(p);
	break;
      case 'U':
	t = ULONG;	l = 4;
	if (string[1]=='S') { t = USHORT; l = 2; }
	break;
      }
      id->ffd->df[n].type = t;
      id->ffd->df[n].loc = loc;
      id->ffd->df[n].len = l;
      loc += l;
    }
    if (fseek(ffh,0L,0)) goto herrorret;
  }

/* Cross-reference */
/* leel 01/30/98 add crossreference to self */
  id->ffd->ffd=id->ffh->ffd = id->ffd;
  id->ffh->ffh=id->ffd->ffh = id->ffh;
  id->ffh->id = id;
  id->ffd->id = id;
  if (ff_stdout != NULL) fflush (ff_stdout);
ret:
  return id;
memerr:
  if (ff_stdout != NULL) fflush(ff_stdout);

  if (ff_stderr != NULL)
#ifndef LINUX
    fprintf(ff_stderr,"Flat file error: %s : %s\n",
            fname,sys_errlist[errno]);
#else
    fprintf(ff_stderr,"Flat file error: %s : %s\n",
            fname,strerror(errno));
#endif
  goto freemem;
hreaderror:
  if (ferror(ffh)) goto herrorret;
  if (ff_stderr != NULL)
    fprintf(ff_stderr,"Flat file error: %s : EOF while reading header file\n",
	id->ffh->name);
  errno = EIO;
  goto freemem;
herrorret:
  id->ffh->error = errno;
  ff_reporterror(id->ffh);
  goto freemem;
derrorret:
  id->ffd->error = errno;
  ff_reporterror((FF_HID *)id->ffd);
freemem:
  if (id) {
    if (id->ffd) {
      if (id->ffd->df) free (id->ffd->df);
      if (id->ffd->fp) fclose (id->ffd->fp);
      if (id->ffd->name) free (id->ffd->name);
      free(id->ffd);
    }
    if (id->ffh) {
      if (id->ffh->fp) fclose (id->ffh->fp);
      if (id->ffh->name) free (id->ffh->name);
      free(id->ffh);
    }
    free(id);
  }
  id = NULL;
  goto ret;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        | ff_close- Closeflat file pair                            */
/* USAGE           | int  ff_close(FF_ID *id);                                */
/* RETURN          | Success 0; Error EOF, check errno:                       */
/* PARAMETER       I FF_ID *id - flatfile struct pointer                      */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_close (FF_ID *id){
  int status;
  long nrows,pos;
  char headerrec[74];
  int ierr=0;
  FILE *ffh;

  if (id < (FF_ID *)ff_minid || (id > (FF_ID *)ff_maxid) || id->type != FF_MAINID) {
    errno = EBADF;
    ff_routineerror("ff_close()");
    return EOF;
  }

  status = id->status;

  ffh = id->ffh->fp;
  if (status & FF_CREATE) 
  	if (fprintf (ffh,FF_FORMAT,"END")==EOF) goto herrorret;
/*
  Warning, if the file was not opened FF_CREATE and if fwrite is called
  instead of ff_put and ff_cput then updated will not be set.

  Possibilities:	Action
  FF_CREATE		Set nrows to current position

  !FF_CREATE | FF_WRITE
			Set nrows to current position which may truncate
			the file if the last write was not at the end!
			In this case the user should to a fseek or ff_setrow
			to the last row.
			Don't know how to find current length of file.
			How about { fseek(fp,0,2); ftell(fp); } ?
			id->size is the size when it was opened.
*/
  if (status & FF_WRITE) {
    if ((pos = ftell(id->ffd->fp)) < 0) goto derrorret;

/* If file was not created and was opened for write when write UPDATE field*/
    if ( !(status & FF_CREATE) ) {
      if (fseek(ffh,72L,0)) goto herrorret;

/* If this read generates EOF the error will be 0, but this shouldn't happen */
      if (fread (headerrec,72,1,ffh) != 1) goto herrorret;
      strcpy(headerrec+36,"  UPDATE =");
      t_con_c (t_now(),headerrec+46);
      headerrec[70] = ' ';
      headerrec[71] = ' ';
      headerrec[72] = '\0';
      if (fseek(ffh,72L,0)) goto herrorret;
      if (fwrite (headerrec,72,1,ffh) != 1) goto herrorret;
    }
/* If open for write, then post NROWS if it has increased. */
    if ( pos > id->ffd->size ) {
      nrows = pos / id->ffd->recl;
      if (fseek(ffh,4*72L,0)) goto herrorret;
      if (fprintf(ffh,"NROWS =%11d%-54c",nrows,' ')==EOF) goto herrorret;
    }
  }
  goto freemem;
herrorret:
  id->ffh->error = errno;
  ff_reporterror(id->ffh);
  ierr = EOF;
  goto freemem;
derrorret:
  id->ffd->error = errno;
  ff_reporterror((FF_HID *)id->ffd);
  ierr = EOF;
  goto freemem;
freemem:
  if (id) {
    if (id->ffd) {
      if (id->ffd->df) free (id->ffd->df);
      if (id->ffd->fp) fclose (id->ffd->fp);
      if (id->ffd->name) free (id->ffd->name);
      free(id->ffd);
    }
    if (id->ffh) {
      if (id->ffh->fp) fclose (id->ffh->fp);
      if (id->ffh->name) free (id->ffh->name);
      free(id->ffh);
    }
    free(id);
  }
  return ierr;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        | ff_put  - Write a Flat file record                       */
/* USAGE           | int ff_put(FF_DID *id,char *record,int len);             */
/* RETURN          | Success>0; Number bytes written                          */
/*                 | Error -1; id->error for error information                */
/* PARAMETER       I FF_ID *id - flatfile struct pointer                      */
/* PARAMETER       I char  *record - data to be written                       */
/* PARAMETER       I int   len     - record length in char                    */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_put(FF_DID *id,char *record,int len){
#ifdef INTEL
/* Leel 09/09/03 make a buffer so not to contaminate data */
static int bufsiz=0;
static char *cptr=NULL;
#endif
  int l;


  if (id < (FF_DID *)ff_minid || id > (FF_DID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_put()");
    return -1;
  }

  switch (id->type) {
    case FF_MAINID:
      id = id->ffd;
    case FF_HEADER:
    case FF_DATA:
      break;
    default:
      errno = EBADF;
      ff_routineerror("ff_put()");
      return -1;
  }
#ifdef INTEL
   if(bufsiz<len) {
     if(cptr==NULL) free(cptr);
     cptr=(char *)malloc(sizeof(char)*len);
     bufsiz=len;
   }
   memcpy(cptr,record,len);
   FFSwapRecords(cptr,len);
  if ((l = fwrite (cptr,1,len,id->fp)) == 0) 
  	if (ferror(id->fp)) goto errorret;
#else  
  if ((l = fwrite (record,1,len,id->fp)) == 0) 
  	if (ferror(id->fp)) goto errorret;
#endif
  return l;
errorret:
  id->error = errno;
  return -1;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        | ff_get  - Read  a Flat file record                       */
/* USAGE           | int ff_get(FF_DID *id,char *record,int len);             */
/* RETURN          | Success >0,number bytes read;                            */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_ID *id - flatfile struct pointer                      */
/* PARAMETER       O char  *record - data to be written                       */
/* PARAMETER       I int   len     - record length in char                    */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_get(FF_DID *id,char *record,int len){
  int l,recl;
  long pos;

  if (id < (FF_DID *)ff_minid || id > (FF_DID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_get()");
    return -1;
  }

  switch (id->type) {
    case FF_MAINID: 
      id = id->ffd;
    case FF_DATA:
      recl = id->recl;
      break;
    case FF_HEADER:
      recl = 72;
      break;
    default:
      errno = EBADF;
      ff_routineerror("ff_get()");
      return -1;
  }
  if ((l = fread (record,1,len,id->fp)) == 0) 
	if (ferror(id->fp)) goto errorret;
#ifdef INTEL
   FFSwapRecords(record,len);
#endif
  if (l % recl) {
    if ( (pos = ftell(id->fp)) < 0) goto errorret;
    pos = (long)(ceil( (double)pos / recl) * recl);
    if (fseek(id->fp,pos,0)) goto errorret;
  }

  return l;
errorret:
  id->error = errno;
  return -1;
} 

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        | f ff_cget - Read a character string from header file.    */
/* USAGE           | int ff_cget(FF_HID *id,char *record);                    */
/* RETURN          | Success >0,number bytes read;(72)                        */
/*                 C Error -1; id->error for error information                */
/*                 C EOF    0;                                                */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* PARAMETER       O char  *record - data read                                */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/

int ff_cget(FF_HID *id,char *record){
  int l;
  char *p;

  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_cget()");
    return -1;
  }
  switch (id->type) {
    case FF_MAINID:
    case FF_DATA:
      id = id->ffh;
    case FF_HEADER:
      break;
    default:
      errno = EBADF;
      ff_routineerror("ff_cget()");
      return -1;
  }

  if ((l = fread (record,72,1,id->fp)) == 0) 
	if (ferror(id->fp)) goto errorret;

  for (p = record+71; p >= record && *p==' '; p--);
  *++p = '\0';
  return l*72;
errorret:
  id->error = errno;
  return -1;
} 

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        |   ff_cput - Write a character string to a header file.   */
/* USAGE           | int ff_cput(FF_HID *id,char *record);                    */
/* RETURN          | Success >0,number bytes read;(72)                        */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* PARAMETER       O char  *record - data to be written                       */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_cput(FF_HID *id,char *record){
  int l;

  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_cput()");
    return -1;
  }
  switch (id->type) {
    case FF_MAINID:
    case FF_DATA:
      id = id->ffh;
    case FF_HEADER:
      break;
    default:
      errno = EBADF;
      ff_routineerror("ff_cput()");
      return -1;
  }

  if ((l = fprintf(id->fp,"%-72.72s",record)) != 72)
  	if (ferror(id->fp)) goto errorret;

  return l;
errorret:
  id->error = errno;
  return -1;
}

int ff_buildname (inname,outname,type,path)
  char *inname,*outname;
  int type,path;
{
  char *p,*n;
  strcpy(outname,inname);
  n = outname;
  if (!path) if ((p=strrchr(outname,'/')) != NULL) 
  	while (*++p != '\0') *n++ = *p;
  if ((p=strsrch(outname,".ffh")) != NULL) *p = '\0';
  if ((p=strsrch(outname,".ffd")) != NULL) *p = '\0';
  if (type==FF_DATA) strcat (outname,".ffd");
  else strcat (outname,".ffh");
  return strlen(outname);
}

char *strsrch(string1,string2)
  char *string1,*string2;
{
  char *ptr,*strchr();
  int strcmp(),l;

  l = (int)strlen(string2);
  while ( (ptr = strchr(string1,*string2)) != NULL && 
          strncmp(ptr,string2,l) ) string1 = ++ptr;
  return ptr;
}


/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        |  ff_setrow - Position flatfile.by row                    */
/* USAGE           | long ff_setrow(FF_DID *id,long row);                     */
/* RETURN          | Success >=0;row number                                   */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* PARAMETER       I long row - row to set                                    */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
long ff_setrow(FF_DID *id,long row){
  int recl;

  if (id < (FF_DID *)ff_minid || id > (FF_DID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_setrow()");
    return -1;
  }

  switch (id->type) {
    case FF_MAINID:
      id = id->ffd;
    case FF_DATA:
      recl = id->recl;
      break;
    case FF_HEADER:
      recl = 72;
      break;
    default:
      errno = EBADF;
      ff_routineerror("ff_setrow()");
      return -1;
  }
  if (fseek(id->fp,row*recl,0)) goto errorret;
  return row;
errorret:
  id->error = errno;
  return -1;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        |  ff_getrow - Return current position by row              */
/* USAGE           | long ff_getrow(FF_DID *id);                              */
/* RETURN          | Success >=0;row number                                   */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_DID *id - flatfile data struct pointer                */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
long ff_getrow(FF_DID *id){
  long nrow;
  int recl;

  if (id < (FF_DID *)ff_minid || id > (FF_DID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_getrow()");
    return -1;
  }
  switch (id->type) {
    case FF_MAINID:
      id = id->ffd;
    case FF_DATA:
      recl = id->recl;
      break;
    case FF_HEADER:
      recl = 72;
      break;
    default:
      errno = EBADF;
      ff_routineerror("ff_getrow()");
      return -1;
  }

  if ( (nrow = ftell(id->fp)) < 0) goto errorret;

  nrow /= recl;
  if (fseek(id->fp,nrow*recl,0)) goto errorret;
  return nrow;
errorret:
  id->error = errno;
  return -1;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        |  ff_hput - Write  character fields to a header file.     */
/* USAGE           | int ff_hput(FF_HID *id,FF_COL_DESC *hr);                 */
/* RETURN          | Success >=0;number bytes written(72)                     */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_DID *id - flatfile data struct pointer                */
/* PARAMETER       I FF_COL_DESC *hr - column description array               */
/*                 C  NAME,UNITS,SOURCE,data TYPE,record LOCation             */
/* UPDATES Apr18,91U Now builds datafields structure.                         */
/* UPDATES May21,92U Changed source field to allow for the full 26 characters */
/*                 C available to it (from 24 characters).  See also the      */
/*                 C changes to ff_hget.  These changes work OK for FFSR,     */
/*                 C hopefully they won't cause any harm elsewhere.  HH       */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_hput(FF_HID *id,FF_COL_DESC *hr){
#ifdef USEIT
  extern int eoffset;
#endif
  int l,n,t;
  char *p,*type;
  char *uptr,*sptr,*fptr;
  char format[80];
  int unitLen;
  char buffer[80];
  int nc;
 
  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_hput()");
    return -1;
  }
  switch (id->type) {
    case FF_MAINID:
      id = id->ffh;
    case FF_HEADER:
      break;
    default:
      id->ffh->error = EBADF;
      ff_routineerror("ff_hput()");
      return -1;
  }

  if (id->ffd->df==NULL) if ((id->ffd->df =
	(struct ff_datafields *)malloc(sizeof(struct ff_datafields)*id->ffd->ncols))==NULL)
	  goto errorret;

  if (hr->ncol == 1) id->loc = 0;

/* Remove leading blanks */
  for (type=hr->type; *type==' '; type++);

  for (p=type; *p != '\0'; p++) if (islower(*p)) *p = toupper(*p);

  switch (type[0]) {
  case 'T': t = TIME66;	l = 8; break;
  case 'D': t = DOUBLE;	l = 8; break;
  case 'B': t = BYTE;	l = 1; break;
  case 'L': t = LONG;	l = 4; break;
  case 'S': t = SHORT;	l = 2; break;
  case 'R': t = FLOAT;	l = 4;
    if (!strcmp(type,"R*8")) {
      l = 8;
      if (hr->ncol == 1 ) { t = TIME66; strcpy(hr->type,"T"); }
      else { t = DOUBLE; strcpy(hr->type,"D"); }
    }
    break;
  case 'I': t = LONG;	l = 4;
    if (strchr(type,'2')!=NULL) { l = 2; t = SHORT; }
    break;
  case 'A':
    t = CHAR;
    for (p = type+1; *p != '\0' && !isdigit(*p); p++) ;
    l = atoi(p);
    break;
  case 'U': t = ULONG;	l = 4;
    if (type[1]=='S') { t = USHORT; l = 2; }
    break;
  default:
    if (ff_stderr != NULL)
      fprintf(ff_stderr,"Flat file error: ff_hput : Illegal data type: %s:%s:\n",
	hr->type,type);
    if (hr->ncol == 1 ) { t = TIME66; strcpy(hr->type,"T"); l = 8; }
    else { t = FLOAT; strcpy(hr->type,"R"); l = 4; }
  }
  n = hr->ncol - 1;
  id->ffd->df[n].type = t;
  id->ffd->df[n].loc = id->loc;
  id->ffd->df[n].len = l;

  /******************************************************************
   * The old VAX code read:
   *
   * if (fprintf(id->fp,"%03d %-10.10s%-10.10s%-24.24s  %-4.4s%5d%13c",
   *   hr->ncol,hr->name,hr->units,hr->source,hr->type,id->loc,' ') == EOF)
   *       goto errorret;
   ******************************************************************
   * The old UNIX code read:
   *
   * if (fprintf(id->fp,"%3.3d %-10.10s%-10.10s%-24.24s  %-4.4s%5d%13c",
   *   hr->ncol,hr->name,hr->units,hr->source,hr->type,id->loc,' ') == EOF)
   *       goto errorret;
   ******************************************************************/
  nc = hr->ncol + NSTARTCOLDESC + id->ffh->eoffset;
  if (fseek(id->fp,(nc)*72L,0)) goto errorret; /*now put in it in the proper place */

  unitLen=id->ffh->fmunit;
  hr->name[10] = '\0';
  hr->units[unitLen] = '\0';
  hr->source[26] = '\0';
  for (p=hr->name+9; *p==' ' && p >= hr->name; p--) *p='\0';
  sprintf(format0,"%s%d.%d%s%dc",formatA,unitLen,unitLen,formatB,21-unitLen);
  if (fprintf(id->fp,format0,
      hr->ncol,hr->name,hr->units,hr->source,hr->type,id->loc,' ') == EOF)
	goto errorret;
if(0)  fprintf(stdout,format0,
      hr->ncol,hr->name,hr->units,hr->source,hr->type,id->loc,' ');

  id->loc += l;
  return 72;
errorret:
  id->error = errno;
  return -1;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        | ff_hget - Read character fields from a header file.      */
/* USAGE           | int ff_hget(FF_HID *id,FF_COL_DESC *hr);                 */
/* RETURN          | Success  72:umber bytes read   (72)                      */
/*                 C Can't Read : 1, No error or EOF but data record not      */
/*                 C               standard                                   */
/*                 C EOF       0                                              */
/*                 C Error     -1 : see id->error for information             */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* PARAMETER       I FF_COL_DESC *hr - column description array               */
/*                 C  NAME,UNITS,SOURCE,data TYPE,record LOCation             */
/* UPDATES May21,92U Changed source field to allow for the full 26 characters */
/*                 C available to it (from 24 characters).  See also the      */
/*                 C changes to ff_hget.  These changes work OK for FFSR,     */
/*                 C hopefully they won't cause any harm elsewhere.  HH       */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_hget(FF_HID *id,FF_COL_DESC *hr){
  int nc;
  char *p,*fptr;
  char format[80]; /* format in reading the file column descriptors */
  char buffer[80]; 
  int  unitLen;
  static const int oldUnitLen=10;
  char *uptr,*sptr; /* start of UNIT , start of NAMES */

  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_hget()");
    return -1;
  }
  switch (id->type) {
    case FF_MAINID:
      id = id->ffh;
    case FF_HEADER:
      break;
    default:
      id->ffh->error = errno = EBADF;
      ff_routineerror("ff_hget()");
      return -1;
  }

  /******************************************************************
   * The old code read:
   *
   * if (fscanf(id->fp,"%3d%*c%10c%10c%24c%4s%d",
   *       &hr->ncol,hr->name,hr->units,hr->source,hr->type,&hr->loc)
   *       !=6) goto headererror;
   *
   * Note that the fscanf format has a bug in it, it should read:
   *                   "%3d%*c%10c%10c%24  c%4s%d"
   * The two missing blanks after the 24 would cause a parsing error
   * if the "source" was 25 characters since the 25th character was
   * read as the type, the blank character 26 delimited the string
   * so that fscanf tried to read the type item as the location value.
   ******************************************************************
   * Also changed were:
   *
   * hr->source[24] = '\0';
   * for (p=hr->source+23; *p==' ' && p >= hr->source; p--) *p='\0';
   ******************************************************************/

/* leel 11/30/00 figure out the format:  use headers to determine   */
/*               the number of character to write                   */
  if (fseek(id->fp,(NSTARTCOLDESC+id->ffh->eoffset)*72L,0)) goto errorret;
  fscanf(id->fp,"%72c",buffer);
  uptr=strstr(buffer,"UNIT");
  sptr=strstr(buffer,"SOURCE");
  unitLen=sptr-uptr;
  sprintf(format0,"%s%d%s",formata,unitLen,formatb);
  nc = hr->ncol + NSTARTCOLDESC + id->ffh->eoffset;
#ifndef PC
  bzero(hr->source,FF_COL_SOURCELEN);
#endif
  if (fseek(id->fp,nc*72L,0)) goto errorret;
  if (fscanf(id->fp,format0,&hr->ncol,hr->name,hr->units,hr->source,hr->type,&hr->loc)!=6) 
      goto headererror;

  hr->name[10] = '\0';
  hr->units[unitLen] = '\0';
  hr->source[26] = '\0';
  for (p=hr->name+9; *p==' ' && p >= hr->name; p--) *p='\0';
  for (p=hr->units+unitLen-1; *p==' ' && p >= hr->units; p--) *p='\0';
  for (p=hr->source+25; *p==' ' && p >= hr->source; p--) *p='\0';
  return 72;
errorret:
  id->error = errno;
  return -1;
headererror:
  if (feof(id->fp)) {
    hr->name[0] = '\0';
    hr->units[0] = '\0';
    hr->source[0] = '\0';
    hr->type[0] = '\0';
    return 0;
  }
  else if (ferror(id->fp)) {
    id->error = errno;
    return -1;
  }
  return 1;
} 

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        |  ff_hgetinfo - Read keyword fields from a header file.   */
/* USAGE           | int ff_hput(FF_HID *id,FF_H_INFO *info);                 */
/* RETURN          | Success >=0;number bytes read   (72)                     */
/*                 C EOF        0 :                                           */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* PARAMETER       I FF_H_INFO *info - file descriptor header                 */
/*                 C  first/last times,resolution,error,owner,first/last orbit*/
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_hgetinfo(FF_HID *id,FF_H_INFO *info){

  int i,l,nkey,hr,min,sec,msec,nmatch,match[NKEY];
  char *peq,headerrec[76];
  int itmp;

  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_hgetinfo()");
    return -1;
  }
  switch (id->type) {
    case FF_MAINID:
      id = id->ffh;
    case FF_HEADER:
      break;
    default:
      id->ffh->error = errno = EBADF;
      ff_routineerror("ff_hgetinfo()");
      return -1;
  }

  info->first_time = -1.e34;
  info->last_time =  1.e34;
  info->owner[0] = '\0';
  info->flag =  1.e34;
  info->resolution = -1.e34;
  info->first_orbit = info->last_orbit = 0;

  for (i=0; i<NKEY; i++) match[i] = 0;
  nmatch = 0;

  if (ff_setrow((FF_DID *)id,(long)(id->ffd->ncols+8)) < 0) return -1;

  while (nmatch < NKEY && (l=ff_cget(id,headerrec)) > 0) {

    nkey = NKEY;
    if ((peq = strchr(headerrec,'=')) != NULL) {
      for (nkey=0; nkey<NKEY && strncmp(keywords[nkey],headerrec,lenkey[nkey]);
	  nkey++) ;
    }

    if (nkey == NKEY) {
      if (!strcmp(headerrec,"END")) break;
      if (headerrec[24] != ':' || headerrec[27] != ':') continue;
    }
    else {
      if (!match[nkey]) nmatch++;
      match[nkey] = 1;
      peq++;
    }
    
    switch (nkey) {
      case 0:
        info->first_time = c_con_t(peq);
	      break;
      case 1:
        info->last_time = c_con_t(peq);
      	break;
      case 2:
	/* sprintf(format,"%%%ds",L_cuserid-1); */
	/* sscanf(peq,format,info->owner); */
        memcpy(info->owner,peq,strlen(peq));
        info->owner[strlen(peq)]=0;
      	break;
      case 3:
      	sscanf(peq,"%lf",&info->flag);
      	break;
      case 4:
      	if (strsrch(peq,"UNKNOWN") != NULL) info->resolution = -1.e34;
      	else if (strsrch(peq,"HI") != NULL &&
		 strsrch(peq,"RESOL") != NULL) info->resolution = 0.;
      	else {
      	  sscanf(peq,"%d%*[: ]%d%*[: ]%d%*[. ]%d",&hr,&min,&sec,&msec);
      	  info->resolution = hr * 3600. + min * 60. + sec + msec / 1000.;
	            }
      	break;
      case 5:
      	sscanf(peq,"%d%*[ -]%d",&info->first_orbit,&info->last_orbit);
      	break;
/*
  Old headers, Fortran format  i4,2x,28a,i6,8h  owner=,a
                              orb   time ??            owner
*/
      case 6:
      	if (!match[5]) sscanf(headerrec,"%d",&info->first_orbit);
      	if (!match[0]) info->first_time = c_con_t(headerrec+6);
      	if (!match[2])
		if (peq != NULL) {
		  strncpy(info->owner, peq, 39);
		}
      	break;
      default : /* leel 08/08/03 if no more keywords quit out */
            return(1);
    }
/*    if(nkey==3)return(1); /* leel 05/07/01 last one to get is MISSING DATA FLAG */
  }
  return l;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        |  ff_hputinfo -Write keyword fields from a header file.   */
/* USAGE           | int ff_hputinfo(FF_HID *id,FF_H_INFO *info);             */
/* RETURN          | Success > 0;number bytes written(72)                     */
/*                 C EOF        0 :                                           */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* PARAMETER       I FF_H_INFO *info - standard information in abstract sect  */
/*                 C  FIRST TIME,LAST TIME,RESOLUTION,Flag,OWNER,1st&lastorbit*/
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/

int ff_hputinfo(FF_HID *id,FF_H_INFO *info){
  int ff_hupdinfo(FF_HID *id,FF_H_INFO *info);
  int l,hr,it[8],status;
  char headerrec[76],ct[32];

  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_hputinfo()");
    return -1;
  }

  switch (id->type) {
    case FF_MAINID:
      id = id->ffh;
    case FF_HEADER:
      status = id->id->status;
      break;
    default:
      id->ffh->error = errno = EBADF;
      ff_routineerror("ff_hputinfo()");
      return -1;
  }

  /* If file was not created, then update the header info */
  if (! (status & FF_CREATE)) return ff_hupdinfo(id,info);

  if ((l=ff_cput(id,"ABSTRACT")) != 72) return -1;

  if (fabs(info->first_time) < 1.e15) {
    t_con_c(info->first_time,ct);
    sprintf(headerrec,"%-18s = %s",keywords[0],ct);
    if ((l=ff_cput(id,headerrec)) != 72) return -1;
  }

  if (fabs(info->last_time) < 1.e15) {
    t_con_c(info->last_time,ct);
    sprintf(headerrec,"%-18s = %s",keywords[1],ct);
    if ((l=ff_cput(id,headerrec)) != 72) return -1;
  }

  if (strlen(info->owner)) {
    sprintf(headerrec,"%-18s = %s",keywords[2],info->owner);
    if ((l=ff_cput(id,headerrec)) != 72) return -1;
  }

  sprintf(headerrec,"%-18s = %#13.6G",keywords[3],info->flag);
  if ((l=ff_cput(id,headerrec)) != 72) return -1;

  ct[0] = '\0';
  if (info->resolution > 0. && info->resolution < 1.e12) {
    hr = (int)(info->resolution / 3600.);
    t_con_i(info->resolution,it);
    sprintf(ct,"%6.2d:%.2d:%.2d.%.3d",hr,it[5],it[6],it[7]);
  }
  else if (info->resolution == 0.) strcpy(ct,"HIGH RESOLUTION");
  else strcpy(ct,"UNKNOWN");
  if (ct[0]!='\0') {
    sprintf(headerrec,"%-18s = %s",keywords[4],ct);
    if ((l=ff_cput(id,headerrec)) != 72) return -1;
  }

  if (info->first_orbit) {
    if (info->last_orbit > info->first_orbit)
    	sprintf(headerrec,"%-18s = %6d - %6d",
		keywords[5],info->first_orbit,info->last_orbit);
    else sprintf(headerrec,"%-18s = %6d",keywords[5],info->first_orbit);
    if ((l=ff_cput(id,headerrec)) != 72) return -1;
  }
  return l;

}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        |  ff_hupdinfo - Update keyword fields in a header file.   */
/* USAGE           | int ff_hupdinfo(FF_HID *id,FF_H_INFO *info);             */
/* RETURN          | Success > 0;number bytes written(72)                     */
/*                 C EOF        0 :                                           */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* PARAMETER       I FF_H_INFO *info - standard information in abstract sect  */
/*                 C  FIRST TIME,LAST TIME,RESOLUTION,Flag,OWNER,1st&lastorbit*/
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/

int ff_hupdinfo(FF_HID *id,FF_H_INFO *info){

  int i,lin,lout,nkey,hr,nmatch,match[NKEY],qeof=0,it[8],crow;
  char headerrec[76],ct[32];

  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_hupdinfo()");
    return -1;
  }

  switch (id->type) {
    case FF_MAINID:
      id = id->ffh;
    case FF_HEADER:
      break;
    default:
      id->ffh->error = errno = EBADF;
      ff_routineerror("ff_hputinfo()");
      return -1;
  }

  for (i=0; i<NKEY; i++) match[i] = 0;
  nmatch = 0;

  for (crow=id->ffd->ncols+7; nmatch < NKEY; crow++) {

    if (ff_setrow((FF_DID *)id,crow) < 0) return -1;
    if (!qeof) {
      if ((lin = ff_cget(id,headerrec)) < 0) return -1;
      if ( !lin ) qeof = 1;	/* EOF before END record, shouldn't happen */
      else if (!strcmp(headerrec,"END")) qeof = 1;
    }

    for (nkey=0; nkey<NKEY && strncmp(keywords[nkey],headerrec,lenkey[nkey]);
	nkey++) if (qeof && !match[nkey]) break;
    
    if (nkey == NKEY) {
      if (qeof) break;
      continue;		/* non-keyword statement, read next record */
    }

    if (lin) if (ff_setrow((FF_DID *)id,crow) < 0) return -1;	/* backspace*/
    if (!match[nkey]) {
      nmatch++;
      match[nkey] = 1;
    }
    else {
/* blank out duplicates */
      if ((lout=ff_cput(id," ")) != 72) return -1;
      continue;
    }

    headerrec[0] = '\0';
    
    switch (nkey) {
      case 0:
	if (fabs(info->first_time) < 1.e15) {
	  t_con_c(info->first_time,ct);
	  sprintf(headerrec,"%-18s = %s",keywords[0],ct);
	}
	break;
      case 1:
	if (fabs(info->last_time) < 1.e15) {
	  t_con_c(info->last_time,ct);
	  sprintf(headerrec,"%-18s = %s",keywords[1],ct);
	}
	break;
      case 2:
	sprintf(headerrec,"%-18s = %s",keywords[2],info->owner);
	break;
      case 3:
	sprintf(headerrec,"%-18s = %#13.6G",keywords[3],info->flag);
	break;
      case 4:
	ct[0] = '\0';
	if (info->resolution > 0.) {
	  hr = (int)(info->resolution / 3600.);
	  t_con_i(info->resolution,it);
	  sprintf(ct,"%6.2d:%.2d:%.2d.%.3d",hr,it[5],it[6],it[7]);
	}
	else if (info->resolution == 0.) strcpy(ct,"HIGH RESOLUTION");

	if (ct[0]!='\0') sprintf(headerrec,"%-18s = %s",keywords[4],ct);
	break;
      case 5:
	if (info->first_orbit) {
	  if (info->last_orbit > info->first_orbit)
	      sprintf(headerrec,"%-18s = %6d - %6d",
		      keywords[5],info->first_orbit,info->last_orbit);
	  else sprintf(headerrec,"%-18s = %6d",keywords[5],info->first_orbit);
	}
	break;
    }
    if (headerrec[0] == '\0') {
      if (!qeof &&  (lout=ff_cput(id," ")) != 72) return -1;
    }
    else if ((lout=ff_cput(id,headerrec)) != 72) return -1;
  }
  return lin;

}

/*BEGIN DOCUMENTATION*********************************************************+/
/* FUNCTION        | ff_copyabstract - Copy abstract records from one header  */
/*                 c file ignoring keyword records.                           */
/* USAGE           | int ff_hcopyabstract(FF_HID *idin,FF_HID *idout);        */
/* RETURN          | Success > 0;number bytes written(72)                     */
/*                 C EOF        0 :                                           */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_HID *idin - flatfile data struct pointer              */
/* PARAMETER       I FF_HID *idout- flatfile data struct pointer              */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/

int ff_hcopyabstract(FF_HID *idin,FF_HID *idout){

  int lin,nkey;
  char *p,*peq,headerrec[76];

  p = "ff_copyabstract()";
  if (idin < (FF_HID *)ff_minid || idin > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror(p);
    return -1;
  }
  switch (idin->type) {
    case FF_MAINID:
      idin = idin->ffh;
    case FF_HEADER:
      break;
    default:
      idin->ffh->error = errno = EBADF;
      ff_routineerror(p);
      return -1;
  }

  if (idout < (FF_HID *)ff_minid || idout > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror(p);
    return -1;
  }
  switch (idout->type) {
    case FF_MAINID:
      idout = idout->ffh;
    case FF_HEADER:
      break;
    default:
      idout->ffh->error = errno = EBADF;
      ff_routineerror(p);
      return -1;
  }

  if (ff_setrow((FF_DID *)idin,idin->ffd->ncols+7+idin->ffh->eoffset) < 0) return -1;

  while ( 1 ) {

    headerrec[0]='\0';
    if ((lin = ff_cget(idin,headerrec)) < 0) return -1;
    if ( !lin ) break;	/* EOF before END record, shouldn't happen */

    nkey = NKEY;
    if ((peq = strchr(headerrec,'=')) != NULL) {
      for (nkey=0; nkey<NKEY && strncmp(keywords[nkey],headerrec,lenkey[nkey]);
	  nkey++) ;
    }
    else {
      if (!strcmp(headerrec,"END")) break;
      if (!strcmp(headerrec,"ABSTRACT")) continue;
    }
 
    if (nkey == NKEY) if (ff_cput(idout,headerrec) != 72) return -1;
  }
  return lin;

}

/*BEGIN DOCUMENTATION*********************************************************+/
/* PROCEDURE       |   ff_reporterror - Print error message on ff_stderr      */
/* USAGE           | void ff_reporterror(FF_HID *id);                         */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
void ff_reporterror(FF_HID *id){
  int *err,error;
#ifdef MACOS
  extern const int sys_nerr;
#endif
#ifdef SUN
  extern int sys_nerr;
#endif
  char *name;
  FILE *fp;

  if (ff_stderr == NULL) return;
  if (ff_stdout != NULL) fflush(ff_stdout);

  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid) return;
  switch (id->type) {
    case FF_MAINID:
      if (id->ffh->error) id = id->ffh;
      else if (id->ffd->error) id = (FF_HID *)id->ffd;
      else if (ferror(id->ffh->fp)) {
	id = id->ffh;
	id->error = errno;
      }
      else if (ferror(id->ffd->fp)) {
	id = (FF_HID *)id->ffd;
	id->error = errno;
      }
      else id = id->ffh;
    case FF_HEADER:
    case FF_DATA:
      err = &id->error;
      name = id->name;
      fp = id->fp;
      break;
    default:
      fp = NULL;
      error = errno;
      err = &error;
      name = " ";
  }

#ifndef LINUX
  if (*err >= sys_nerr) 
#else
  if( strerror(*err) == EINVAL )
#endif
      fprintf(ff_stderr,
      "Flat file error: %s : %d (unknown)\n",name,*err);
  else if ( *err ) fprintf(ff_stderr,
#ifndef LINUX
      "Flat file error: %s : %s\n",name,sys_errlist[*err]);
#else
      "Flat file error: %s : %s\n",name,strerror(*err));
#endif

/* fseek/lseek return EINVAL on negative file positions */
  if (*err == EINVAL)
	fprintf(ff_stderr,"  Possible negative row number.\n");

  if (fp) clearerr(fp);
  *err = 0;
  return;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* PROCEDURE       |ff_routineerror-Print error message about routine         */
/* USAGE           |void ff_routineerror(char *s);                            */
/* PARAMETER       I char *s - error message                                  */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/

void ff_routineerror(char *s){
  if (ff_stderr == NULL) return;
  if (ff_stdout != NULL) fflush(ff_stdout);
#ifndef LINUX
  fprintf(ff_stderr,"Flat file error: %s : %s\n",s,sys_errlist[errno]);
#else
  fprintf(ff_stderr,"Flat file error: %s : %s\n",s,strerror(errno));
#endif
  return;
}

/*BEGIN DOCUMENTATION*********************************************************+/
/* PROCEDURE       |ff_hlist - List headerfile to standard output.            */
/* USAGE           |vint ff_hlist(FF_HID *id);                                */
/* RETURN          | Success > 0;number bytes read   (72)                     */
/*                 C Error -1; id->error for error information                */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  12/11/90       */
/*END DOCUMENTATION************************************************************/
int ff_hlist(FF_HID *id){
#ifndef PC
  char command[MAXPATHLEN+20];
  int pipefd[2];
/*   union wait statloc; */
  int	 statloc;
#endif
  if (id < (FF_HID *)ff_minid || id > (FF_HID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_hlist()");
    return -1;
  }
  switch (id->type) {
    case FF_MAINID:
      id = id->ffh;
    case FF_HEADER:
      break;
    default:
      id->ffh->error = errno = EBADF;
      ff_routineerror("ff_hlist()");
      return -1;
  }

  if (ff_stdout == NULL) return 0;
  fflush(ff_stdout);


#ifndef PC
  if (pipe(pipefd) == -1) { id->error = errno; return -1; }
  switch (fork()) {
    case -1: 
      id->error = errno;
      return -1;
    case 0:	/* child, ffhcat */
      close(1);
      dup(pipefd[1]);
      close(pipefd[0]);
      close(pipefd[1]);
      execlp("ffhcat","ffhcat","-i",id->name,(char *)0);
      perror("ffhcat");
      exit(1);
  }
  close(pipefd[1]);
  switch (fork()) {
    case -1: 
      id->error = errno;
      return -1;
    case 0:	/* child, more */
      close(0);
      dup(pipefd[0]);
      close(pipefd[0]);
      close(pipefd[1]);
      if (ff_stdout != stdout && ff_stdout != NULL) {
	close(1);
	if (dup(fileno(ff_stdout))) exit(1);
      }
      if (ff_stderr != stderr && ff_stderr != NULL) {
	close(2);
	if (dup(fileno(ff_stderr))) exit(1);
      }
      execlp("more","more","-d",(char *)0);
      perror("more");
      exit(1);
  }
  close(pipefd[0]);
  wait(&statloc);
  wait(&statloc);
#endif
      
  return 72;
}


/*BEGIN DOCUMENTATION*********************************************************+/
/* PROCEDURE       | ff_bsearch - binary search of time in flat file. Returns */
/*                 C row number of first record whose time is greater than or */
/*                 C equal to the input time.                                 */
/* USAGE           | int ff_hlist(FF_HID *id);                                */
/* RETURN          | Success >=0;row number                                   */
/*                 C Error -1; id->error for error information                */
/*                 C           possible infinite loop in search, time is not  */
/*                 C           monotonically increasing.                      */
/* PARAMETER       I FF_HID *id - flatfile header struct pointer              */
/* CREATOR         | Gordon Maclean  UCLA Inst. of Geophysics  02/06/90       */
/*END DOCUMENTATION************************************************************/
long ff_bsearch(FF_ID *id,double time,long row1,long row2){
  int n,recl;
  long lrow,row;
  double tdata;
  FILE *fp;

  if (id < (FF_ID *)ff_minid || id > (FF_ID *)ff_maxid ) {
    errno = EBADF;
    ff_routineerror("ff_bsearch()");
    return -1;
  }
  switch (id->type) {
    case FF_DATA:
      id = id->id;
    case FF_MAINID:
      break;
    default: 
      id->ffd->error = errno = EBADF;
      return -1;
  }

/*
  Check if file has been extended in FF_WRITE mode.
  Since the rows are numbered from 0, lrow is the row after the last
  (could be 0)
*/
  if (id->status & FF_WRITE) lrow = MAXFF(id->ffd->nrows,ff_getrow(id->ffd));
  else lrow = id->ffd->nrows;

  if ( !lrow ) return lrow;

  if (row1 < 0) row1 = 0;
  if (row1 >= lrow) row1 = lrow-1;	/* Is 0 if lrow = 1 */
  if (row2 <= row1 || row2 > lrow) row2 = lrow;	/* Could be 1 */

/* 
  Maximum number of reads necessary for a binary search.
  The difference between row1 and row2 is repeatedly halved until it is 1.
  2 ** n = (row2-row1)
*/
  n = (int)(log( (double) (row2-row1) ) / log(2.) + 1.5);

  recl = id->ffd->recl;

  fp = id->ffd->fp;
  do {
    row = (row2 + row1) / 2;
    if (fseek(fp,row * recl,0)) goto errorret;

/* Shouldn't get an EOF if nrows is correct */
    if (fread (&tdata,sizeof(tdata),1,fp) == 0) goto errorret;
    if ( n-- == 0) goto time_err;

    if (tdata < time) row1 = row;
    else row2 = row;

  } while (row1+1 < row2 );

  row = row2;

/* Perhaps even the first row is after time */
  if (row1 == 0) {
    if (fseek(fp,0L,0)) goto errorret;
    if (fread (&tdata,sizeof(tdata),1,fp) == 0) goto errorret;
    if (tdata >= time) row = row1;
  }
  if (fseek(fp,row * recl,0)) goto errorret;
  return row;
errorret:
  if (feof(fp)) id->ffd->error = errno;
  return -1;
time_err:
  if (ff_stderr != NULL) fprintf(ff_stderr,
	"Flat file error: %s : ff_bsearch aborting, Time is not ordered.\n",
	id->ffd->name);
  return -1;
}

void PrintFF_DATA(struct ff_data *fptr){
  printf("type %3d Hptr %5d Dptr %5d name %s error %d\n",
          fptr->type,fptr->ffh,fptr->ffd,fptr->name,fptr->error);
  printf("nrows %5d size %5d nrecl %5d ncols %5d epoch %4d\n",
          fptr->nrows,fptr->size,fptr->recl,fptr->ncols,fptr->epoch);
}

void PrintFF_HEADER(struct ff_header *ffh){
  printf("type %3d Hptr %5d Dptr %5d name %s error %d loc %d\n",
          ffh->type,ffh->ffh,ffh->ffd,ffh->name,ffh->error,ffh->loc);
  printf("eoffset %d fmunit %d \n",ffh->eoffset,ffh->fmunit);
}


/* leel 12/01/00 this is to set the new format */
void SetUnitFormat(int len){
    if(len<FF_COL_UNITSLEN) ff_col_format=len;
    else printf("SetUnitFormat: max len is %d \n",FF_COL_UNITSLEN-1);
}
/* leel 08/22/02 Figure out from the header # char need for units */
int GetUnitLength(FF_HID *id){
  int len;
  char buffer[80];
  char *uptr,*sptr;
  long cpos=ftell(id->fp);
  if (fseek(id->fp,(NSTARTCOLDESC+id->eoffset)*72L,0)) 
    goto errorret;
  fscanf(id->fp,"%72c",buffer);
  uptr=strstr(buffer,"UNIT");
  sptr=strstr(buffer,"SOURCE");
  len=sptr-uptr;
  fseek(id->fp,cpos,SEEK_SET);
  return (len);
  errorret:
    printf("Unable to get unit format\n");
    return(-1);
}

void PrintFFColDesc(FF_COL_DESC desc){
  printf("ncol %2d name %10.10s units %s source %24s type %4s loc %3d\n",
  desc.ncol,desc.name,desc.units,desc.source,desc.type,desc.loc);
}

void PrintFFParam(FF_O_PARAM parm){
  printf("status %d recl %d ncols %d nbuf %d nrows %d epoch %d\n",
  parm.status,parm.recl,parm.ncols,parm.nbufs,parm. nrows,parm. epoch);
}


void PrintFFINFO(FF_H_INFO info){
  char buffer0[40],buffer1[40];
  t_con_c(info.first_time,buffer0);
  t_con_c(info.last_time,buffer1);
/*
  printf("%g %g \n",info.first_time,info.last_time);
  printf("first_time %s last_time %s \n",buffer0,buffer1);
  printf("resolution %g flag %g owner %s int first %d last %d\n",
    info.resolution,info.flag,info.owner,
    info.first_orbit,info.last_orbit);
*/
  printf("\tfirst time:%s\n\tlast  time:%s\n",
    buffer0,buffer1);
  printf("\tresolution:%10g\tflag %10g \n",
    info.resolution,info.flag);
  printf("\towner     :\"%s\"\n",info.owner);
  printf("\tfirst orbit:%10d\tlast orbit :%10d \n",
    info.first_orbit,info.last_orbit);

}


void FFSilentMode(){
  extern int ff_silent;
  ff_silent=1;
}

void FFOldStyle(){
  extern int ff_oldstyle;
  ff_oldstyle=1;
}

#ifdef INTEL
/* leel 2003 NOV 14 FORTRAN WRAPPER */
void ffswaprecords_(char * binary,int *nchar){
  FFSwapRecords(binary,*nchar);
}
#endif
void FFSwapRecords(char * binary,int nchar){
  char tbuff[8],fbuff[4];
  int index,limit,i;
  memcpy(tbuff,binary,8);
  for(i=0;i<8;i++)binary[i]=tbuff[7-i];
  limit=nchar/4;
  for(i=2;i<=limit;i++){
          index=i*4;
          memcpy(fbuff,&binary[index],4);
          binary[index  ]=fbuff[3];
          binary[index+1]=fbuff[2];
          binary[index+2]=fbuff[1];
          binary[index+3]=fbuff[0];
  }
}
