/*===========================================================================
  Copyright (C) 2001 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
  Internet e-mail: midas@eso.org
  Postal address: European Southern Observatory
  Data Management Division 
  Karl-Schwarzschild-Strasse 2
  D 85748 Garching bei Muenchen 
  GERMANY
  ===========================================================================*/
/*-------------------------------------------------------------------------*/
/**
 * @defgroup flames_cubify  Group frame images into cubes
 *
 */
/*-------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
  Includes
  --------------------------------------------------------------------------*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <flames_midas_def.h>
/* FLAMES-UVES include files */ 
#include <flames_cubify.h>
#include <flames_uves.h>
#include <flames_stripfitsext.h>
#include <flames_newmatrix.h>
#include <cpl.h>
/* C functions include files */ 
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*---------------------------------------------------------------------------
  Typedefs
  --------------------------------------------------------------------------*/

typedef struct _specdescriptors
{
  int dattype;
  int nflats;
  int naxis;
  int maxfibres;
  char chipchoice;
  double ron;
  double gain;
  int tab_io_oshift;
  int fibrenum;
  int *npix; /* size 2 */
  double *start; /* size 2 */
  double *step; /* size 2 */
  char *cunit; /* size 49 */
  int *orderlim; /* size 2 */
  float *lhcuts; /* size 4 */
  char *ident; /* size 73 */
  double *yshift; /* size nflats */
  double **wstart; /* size norders */
  int **nptot; /* size norders */
  int *norder; /* size norders */
  char rebinflag;
} specdescriptors;
/*---------------------------------------------------------------------------
  Declarations
  --------------------------------------------------------------------------*/

static flames_err 
free_specdescriptors(specdescriptors *specdescr);

static flames_err 
read_desc_template(char **templatefiles, int nspectra, 
		   specdescriptors *tempdescr) ;


static flames_err 
readcheck_spectrum(char *specfile, specdescriptors *specdescr,
		   char *templatefile, specdescriptors *tempdescr, 
		   char ***charcube, int *fibremask) ;

static flames_err 
write_cube(char *cubename, specdescriptors *tempdescr, 
	   int *fibremask, char ***charcube);

static flames_err 
updatecheck_template(char *newtemplatefile, char *oldtemplatefile, 

		     specdescriptors *tempdescr) ;
/**@{*/

/*---------------------------------------------------------------------------
  Implementation
  ---------------------------------------------------------------------------*/
static flames_err 
read_sigmask_names(char **specnames, int nspectra, 
		   char **sigmanames, char **masknames) ;


static flames_err 
free_specdescriptors(specdescriptors *specdescr) 
{

  free_ivector(specdescr->npix, 0, 1);
  free_dvector(specdescr->start, 0, 1);
  free_dvector(specdescr->step, 0, 1);
  free(specdescr->cunit);
  free_ivector(specdescr->orderlim, 0, 1);
  free_vector(specdescr->lhcuts, 0, 3);
  free(specdescr->ident);
  if (specdescr->nflats>0) {
    free_dvector(specdescr->yshift, 0, specdescr->nflats-1);
  }
  if (specdescr->rebinflag==TRUE) {
    free_dmatrix(specdescr->wstart, 0, specdescr->maxfibres-1, 
		 0, specdescr->npix[1]-1);
    free_imatrix(specdescr->nptot, 0, specdescr->maxfibres-1, 
		 0,specdescr->npix[1]-1);
    free_ivector(specdescr->norder, 0,specdescr->npix[1]-1);
  }

  return NOERR;

}


static flames_err 
read_desc_template(char **templatefiles, int nspectra, 
		   specdescriptors *tempdescr) {

  char type=0;
  char type1=0;
  char type2=0;
  char type3=0;
  int noelem=0;
  int noelem1=0;
  int noelem2=0;
  int noelem3=0;
  int bytelem=0;
  int specid=0;
  char output[160];
  int actvals=0;
  int unit=0;
  int null=0;
  int ivecbuf[10];
  int i=0;
  char *templatefile=0;

  memset(output, 0, 160);

  /* since different spectra may have been rebinned with slightly different 
     wavelength calibrations, they may also have slightly different NPIX[2], 
     hence I need to scan all files and use the maximum value */
  /* this makes sure that we put there the NPIX taken from a frame */
  tempdescr->npix[0] = -1;
  for (i=0; i<=(nspectra-1); i++) {
    templatefile = templatefiles[i];
    /* get the dattype of the template file */
    if (SCFINF(templatefile, 4, ivecbuf)!=0) {
      sprintf(output, "Error opening file %s", templatefile);
      SCTPUT(output);
      return MAREMMA;
    }
    tempdescr->dattype = ivecbuf[1];
    /* open the i-th spectrum */
    if (SCFOPN(templatefile, tempdescr->dattype, 0, F_IMA_TYPE, &specid)!=0) {
      sprintf(output, "Error opening spectrum file %s", templatefile);
      SCTPUT(output);
      return MAREMMA;
    }
    /* read NAXIS and NPIX */
    if ((SCDRDI(specid, "NAXIS", 1, 1, &actvals, ivecbuf, &unit, 
		&null)!=0) || (actvals!=1)) {
      sprintf(output, "Error reading NAXIS from spectrum file %s", 
	      templatefile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", templatefile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
    /* is naxis correct? */
    if (ivecbuf[0]!=2) {
      sprintf(output, "Error: spectrum file %s has unsupported NAXIS value", 
	      templatefile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", templatefile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
    if ((SCDRDI(specid, "NPIX", 1, 1, &actvals, ivecbuf, &unit, &null)
	 !=0) || (actvals!=1) || (ivecbuf[0]<0)) {
      sprintf(output, "Error reading NPIX from spectrum file %s", 
	      templatefile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", templatefile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
    if (tempdescr->npix[0]<ivecbuf[0]) tempdescr->npix[0] = ivecbuf[0];
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
      return MAREMMA;
    }
  }

  templatefile = templatefiles[0];
  /* get the dattype of the template file */
  if (SCFINF(templatefile, 4, ivecbuf)!=0) {
    sprintf(output, "Error opening file %s", templatefile);
    SCTPUT(output);
    return MAREMMA;
  }
  tempdescr->dattype = ivecbuf[1];
  /* open the i-th spectrum */
  if (SCFOPN(templatefile, tempdescr->dattype, 0, F_IMA_TYPE, &specid)!=0) {
    sprintf(output, "Error opening spectrum file %s", templatefile);
    SCTPUT(output);
    return MAREMMA;
  }
  /* read the important descriptors */
  if ((SCDRDC(specid, "IDENT", 1, 1, 72, &actvals, tempdescr->ident, &unit, 
	      &null)!=0) || (actvals!=72)) {
    sprintf(output, "Error reading IDENT from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "NAXIS", 1, 1, &actvals, &tempdescr->naxis, &unit, &null)
       !=0) || (actvals!=1)) {
    sprintf(output, "Error reading NAXIS from spectrum file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  /* is naxis correct? */
  if (tempdescr->naxis!=2) {
    sprintf(output, "Error: spectrum file %s has unsupported NAXIS value", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (SCDFND(specid, "YSHIFT", &type, &noelem, &bytelem)!=0) {
    sprintf(output, "Error looking for descriptor YSHIFT in file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  switch(type) {
  case 'D':
    /* yshift is set and is of type double, use it */
    tempdescr->nflats = noelem;
    break;
  case ' ':
    /* yshift is not set, hence nflats=0 */
    tempdescr->nflats = 0;
    break;
  default:
    /* yshift is of the wrong type, set nflats to zero but issue a warning */
    tempdescr->nflats = 0;
    sprintf(output, "Warning: wrong descriptor type for YSHIFT in %s", 
	    templatefile);
    SCTPUT(output);
    break;
  }
  if (tempdescr->nflats>0) {
    tempdescr->yshift = dvector(0,tempdescr->nflats-1);
    if ((SCDRDD(specid, "YSHIFT", 1, tempdescr->nflats, &actvals, 
		tempdescr->yshift, &unit, &null)!=0) || 
	(actvals!=tempdescr->nflats)) {
      sprintf(output, "Error reading YSHIFT from spectrum file %s", 
	      templatefile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", templatefile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
  }
  /* only read the second value of NPIX, since the first was previously set
     scanning all the spectra */
  if ((SCDRDI(specid, "NPIX", 2, 1, &actvals, tempdescr->npix+1, &unit, &null)
       !=0) || (actvals!=1)) {
    sprintf(output, "Error reading NPIX from spectrum file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "START", 1, 2, &actvals, tempdescr->start, &unit, &null)
       !=0) || (actvals!=2)) {
    sprintf(output, "Error reading START from spectrum file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "STEP", 1, 2, &actvals, tempdescr->step, &unit, &null)
       !=0) || (actvals!=2)) {
    sprintf(output, "Error reading STEP from spectrum file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDC(specid, "CUNIT", 1, 1, 48, &actvals, tempdescr->cunit, &unit, 
	      &null)!=0) || (actvals!=48)) {
    sprintf(output, "Error reading CUNIT from spectrum file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "MAXFIBRES", 1, 1, &actvals, &tempdescr->maxfibres, 
	      &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading MAXFIBRES from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDC(specid, "CHIPCHOICE", 1, 1, 1, &actvals, &tempdescr->chipchoice, 
	      &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading CHIPCHOICE from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "RON", 1, 1, &actvals, &tempdescr->ron, &unit, &null)!=0)
      || (actvals!=1)) {
    sprintf(output, "Error reading RON from spectrum file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "GAIN", 1, 1, &actvals, &tempdescr->gain, &unit, &null)
       !=0) || (actvals!=1)) {
    sprintf(output, "Error reading GAIN from spectrum file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "ORDERLIM", 1, 2, &actvals, tempdescr->orderlim, &unit, 
	      &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading ORDERLIM from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  /* is ORDERLIM consistent? */
  if (((tempdescr->orderlim[1]>=tempdescr->orderlim[0]) &&
       ((tempdescr->orderlim[1]+1-tempdescr->orderlim[0])!=tempdescr->npix[1]))
      || ((tempdescr->orderlim[1]<tempdescr->orderlim[0]) &&
	  ((tempdescr->orderlim[0]+1-tempdescr->orderlim[1])
	   !=tempdescr->npix[1]))) {
    sprintf(output,"Error: ORDERLIM inconsistent with NPIX in file %s", templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "TAB_IN_OUT_OSHIFT", 1, 1, &actvals, 
	      &tempdescr->tab_io_oshift, &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading TAB_IN_OUT_OSHIFT from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  /* is this spectrum rebinned? look for WSTART, NPTOT and NORDER */
  if (SCDFND(specid, "WSTART", &type1, &noelem1, &bytelem)!=0) {
    sprintf(output, "Error searching WSTART from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (SCDFND(specid, "NPTOT", &type2, &noelem2, &bytelem)!=0) {
    sprintf(output, "Error searching NPTOT from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (SCDFND(specid, "NORDER", &type3, &noelem3, &bytelem)!=0) {
    sprintf(output, "Error searching NORDER from spectrum file %s", 
	    templatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", templatefile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  /* what did I find? */
  if ((type1=='D') && (type2=='I') && (type3=='I') && 
      (noelem1==tempdescr->npix[1]) && (noelem2==noelem1) &&
      (noelem3==noelem1)) {
    SCTPUT("WSTART, NPTOT and NORDER present and of the right size and type,");
    SCTPUT("assume rebinned input spectra");
    /* this looks like a rebinned spectrum, set things up accordingly */
    tempdescr->rebinflag=TRUE;
    tempdescr->wstart = dmatrix(0, tempdescr->maxfibres-1, 
				0, tempdescr->npix[1]-1);
    tempdescr->nptot = imatrix(0, tempdescr->maxfibres-1, 
			       0, tempdescr->npix[1]-1);
    tempdescr->norder = ivector(0,tempdescr->npix[1]-1);
    /* read the additional descriptors */
    if ((SCDRDI(specid, "NORDER", 1, tempdescr->npix[1], &actvals, 
		tempdescr->norder, &unit, &null)!=0) || 
	(actvals!=tempdescr->npix[1])) {
      sprintf(output, "Error reading NORDER from spectrum file %s", 
	      templatefile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", templatefile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
  }
  else {
    SCTPUT("WSTART, NPTOT or NORDER absent or of wrong type or size");
    SCTPUT("assuming unrebinned input spectra");
    tempdescr->rebinflag=FALSE;
  }
  /* close the template spectrum */
  if (SCFCLO(specid)!=0) {
    sprintf(output, "Error closing spectrum file %s", templatefile);
    SCTPUT(output);
    return MAREMMA;
  }

  return NOERR;

}


static flames_err 
readcheck_spectrum(char *specfile, specdescriptors *specdescr,
		   char *templatefile, specdescriptors *tempdescr, 
		   char ***charcube, int *fibremask) 
{

  char type=0;
  int noelem=0;
  int bytelem=0;
  int specid=0;
  char output[160];
  int actvals=0;
  int unit=0;
  int null=0;
  int ivecbuf[10];
  int i=0;
  frame_data ***speccube=0;
  frame_mask ***maskcube=0;
  float ***fmaskcube=0;


  memset(output, 0, 160);

  /* check dattype consistency */
  if (SCFINF(specfile, 4, ivecbuf)!=0) {
    sprintf(output, "Error opening file %s", specfile);
    SCTPUT(output);
    return MAREMMA;
  }
  specdescr->dattype = ivecbuf[1];
  if (specdescr->dattype != tempdescr->dattype) {
    sprintf(output, "Error: dattype mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    return MAREMMA;
  }
  /* open the spectrum */
  if (SCFOPN(specfile, tempdescr->dattype, 0, F_IMA_TYPE, &specid)!=0) {
    sprintf(output, "Error opening spectrum file %s", specfile);
    SCTPUT(output);
    return MAREMMA;
  }
  /* read the descriptors and compare them with the template */
  if ((SCDRDC(specid, "IDENT", 1, 1, 72, &actvals, specdescr->ident, &unit, 
	      &null)!=0) || (actvals!=72)) {
    sprintf(output, "Error reading IDENT from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (strncmp(specdescr->ident, tempdescr->ident, 72)!=0) {
    sprintf(output, "Error: IDENT mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "NAXIS", 1, 1, &actvals, &specdescr->naxis, &unit, 
	      &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading NAXIS from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (specdescr->naxis != tempdescr->naxis) {
    sprintf(output, "Error: Unsupported NAXIS in spectrum %s",
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (SCDFND(specid, "YSHIFT", &type, &noelem, &bytelem)!=0) {
    sprintf(output, "Error looking for descriptor YSHIFT in file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  switch(type) {
  case 'D':
    /* yshift is set and is of type double, use it */
    specdescr->nflats = noelem;
    break;
  case ' ':
    /* yshift is not set, hence nflats=0 */
    specdescr->nflats = 0;
    break;
  default:
    /* yshift is of the wrong type, set nflats to zero but issue a warning */
    specdescr->nflats = 0;
    sprintf(output, "Warning: wrong descriptor type for YSHIFT in %s", 
	    specfile);
    SCTPUT(output);
    break;
  }
  if (specdescr->nflats != tempdescr->nflats) {
    sprintf(output, "Error: YSHIFT size mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (specdescr->nflats>0) {
    if ((SCDRDD(specid, "YSHIFT", 1, specdescr->nflats, &actvals, 
		specdescr->yshift, &unit, &null)!=0) || 
	(actvals!=specdescr->nflats)) {
      sprintf(output, "Error reading YSHIFT from spectrum file %s", 
	      specfile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", specfile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
    for (i=0; i<=(specdescr->nflats-1); i++) {
      if (specdescr->yshift[i] != tempdescr->yshift[i]) {
	sprintf(output, "Error: YSHIFT mismatch between spectra %s and %s",
		templatefile, specfile);
	SCTPUT(output);
	if (SCFCLO(specid)!=0) {
	  sprintf(output, "Error closing spectrum file %s", specfile);
	  SCTPUT(output);
	}
	return MAREMMA;
      }
    }
  }
  if ((SCDRDI(specid, "NPIX", 1, 2, &actvals, specdescr->npix, &unit, 
	      &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading NPIX from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((specdescr->npix[0] > tempdescr->npix[0]) || 
      (specdescr->npix[1] != tempdescr->npix[1])) {
    sprintf(output, "Error: NPIX mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "START", 1, 2, &actvals, specdescr->start, &unit, 
	      &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading START from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((specdescr->start[0] != tempdescr->start[0]) || 
      (specdescr->start[1] != tempdescr->start[1])) {
    sprintf(output, "Error: START mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "STEP", 1, 2, &actvals, specdescr->step, &unit, 
	      &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading STEP from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((specdescr->step[0] != tempdescr->step[0]) || 
      (specdescr->step[1] != tempdescr->step[1])) {
    sprintf(output, "Error: STEP mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDC(specid, "CUNIT", 1, 1, 48, &actvals, specdescr->cunit, &unit, 
	      &null)!=0) || (actvals!=48)) {
    sprintf(output, "Error reading CUNIT from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (strncmp(specdescr->cunit, tempdescr->cunit, 48)!=0) {
    sprintf(output, "Error: CUNIT mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "MAXFIBRES", 1, 1, &actvals, &specdescr->maxfibres, 
	      &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading MAXFIBRES from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (specdescr->maxfibres != tempdescr->maxfibres) {
    sprintf(output, "Error: MAXFIBRES mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDC(specid, "CHIPCHOICE", 1, 1, 1, &actvals, 
	      &specdescr->chipchoice, &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading CHIPCHOICE from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (specdescr->chipchoice != tempdescr->chipchoice) {
    sprintf(output, "Error: CHIPCHOICE mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "RON", 1, 1, &actvals, &specdescr->ron, &unit, 
	      &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading RON from spectrum file %s", specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (specdescr->ron != tempdescr->ron) {
    sprintf(output, "Error: RON mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDD(specid, "GAIN", 1, 1, &actvals, &specdescr->gain, &unit, 
	      &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading GAIN from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (specdescr->gain != tempdescr->gain) {
    sprintf(output, "Error: GAIN mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "ORDERLIM", 1, 2, &actvals, specdescr->orderlim, 
	      &unit, &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading ORDERLIM from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((specdescr->orderlim[0] != tempdescr->orderlim[0]) || 
      (specdescr->orderlim[1] != tempdescr->orderlim[1])) {
    sprintf(output, "Error: ORDERLIM mismatch between spectra %s and %s",
	    templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "TAB_IN_OUT_OSHIFT", 1, 1, &actvals, 
	      &specdescr->tab_io_oshift, &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading TAB_IN_OUT_OSHIFT from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (specdescr->tab_io_oshift != tempdescr->tab_io_oshift) {
    sprintf(output, "Error: TAB_IN_OUT_OSHIFT mismatch between spectra %s \
and %s", templatefile, specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if ((SCDRDI(specid, "FIBRENUM", 1, 1, &actvals, &specdescr->fibrenum, 
	      &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading FIBRENUM from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  /* check fibrenum */
  if ((specdescr->fibrenum<1)||(specdescr->fibrenum>specdescr->maxfibres)) {
    sprintf(output, "Error: inconsistent FIBRENUM in file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  if (fibremask[specdescr->fibrenum-1]==TRUE) {
    SCTPUT("Error: multiple spectra with the same FIBRENUM");
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  fibremask[specdescr->fibrenum-1] = TRUE;
  /* should WSTART, NPTOT and NORDER be defined? */
  if (tempdescr->rebinflag==TRUE) {
    /* just read and store WSTART and NPTOT, which may well be slightly 
       different among fibres */
    if ((SCDRDD(specid, "WSTART", 1, tempdescr->npix[1], &actvals, 
		tempdescr->wstart[specdescr->fibrenum-1], &unit, &null)!=0) || 
	(actvals!=tempdescr->npix[1])) {
      sprintf(output, "Error reading WSTART from file %s", 
	      specfile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", specfile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
    if ((SCDRDI(specid, "NPTOT", 1, tempdescr->npix[1], &actvals, 
		tempdescr->nptot[specdescr->fibrenum-1], &unit, &null)!=0) || 
	(actvals!=tempdescr->npix[1])) {
      sprintf(output, "Error reading NPTOT from file %s", 
	      specfile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", specfile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
    /* read, store and check NORDER, which must remain equal across fibres */
    if ((SCDRDI(specid, "NORDER", 1, tempdescr->npix[1], &actvals, 
		specdescr->norder, &unit, &null)!=0) || 
	(actvals!=tempdescr->npix[1])) {
      sprintf(output, "Error reading NORDER from file %s", 
	      specfile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", specfile);
	SCTPUT(output);
      }
      return MAREMMA;
    }
    for (i=0; i<=(specdescr->npix[1]-1); i++) {
      if (specdescr->norder[i] != tempdescr->norder[i]) {
	sprintf(output, "Error: NPTOT mismatch between spectra %s and %s",
		templatefile, specfile);
	SCTPUT(output);
	if (SCFCLO(specid)!=0) {
	  sprintf(output, "Error closing spectrum file %s", specfile);
	  SCTPUT(output);
	}
	return MAREMMA;
      }
    }
  }
  /* now read descriptors which must be present but need not be compared
     with a template */
  if ((SCDRDR(specid, "LHCUTS", 1, 4, &actvals, specdescr->lhcuts, &unit, 
	      &null)!=0) || (actvals!=4)) {
    sprintf(output, "Error reading LHCUTS from spectrum file %s", 
	    specfile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  /* we can read the spectrum */
  if (tempdescr->dattype==FLAMESDATATYPE) {
    speccube = (frame_data ***) charcube;
    for (i=0; i<=(specdescr->npix[1]-1); i++) {
      if (SCFGET(specid, 1+i*specdescr->npix[0], specdescr->npix[0], &actvals, 
		 (char *) speccube[specdescr->fibrenum-1][i])!=0) {
	sprintf(output, "Error reading file %s", specfile);
	SCTPUT(output);
	if (SCFCLO(specid)!=0) {
	  sprintf(output, "Error closing spectrum file %s", specfile);
	  SCTPUT(output);
	}
	return MAREMMA;
      }
    }
  }
  else if (tempdescr->dattype==FLAMESMASKTYPE) {
    maskcube = (frame_mask ***) charcube;
    for (i=0; i<=(specdescr->npix[1]-1); i++) {
      if (SCFGET(specid, 1+i*specdescr->npix[0], specdescr->npix[0], &actvals, 
		 (char *) maskcube[specdescr->fibrenum-1][i])!=0) {
	sprintf(output, "Error reading file %s", specfile);
	SCTPUT(output);
	if (SCFCLO(specid)!=0) {
	  sprintf(output, "Error closing spectrum file %s", specfile);
	  SCTPUT(output);
	}
	return MAREMMA;
      }
    }
  }
  else if (tempdescr->dattype==D_R4_FORMAT) {
    fmaskcube = (float ***) charcube;
    for (i=0; i<=(specdescr->npix[1]-1); i++) {
      if (SCFGET(specid, 1+i*specdescr->npix[0], specdescr->npix[0], &actvals, 
		 (char *) fmaskcube[specdescr->fibrenum-1][i])!=0) {
	sprintf(output, "Error reading file %s", specfile);
	SCTPUT(output);
	if (SCFCLO(specid)!=0) {
	  sprintf(output, "Error closing spectrum file %s", specfile);
	  SCTPUT(output);
	}
	return MAREMMA;
      }
    }
  }
  else {
    /* we should never get here, but it does not hurt to add this check */
    SCTPUT("Error: unsupported dattype in readcheck_spectrum()");
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", specfile);
      SCTPUT(output);
    }
    return MAREMMA;
  }
  /* close file */
  if (SCFCLO(specid)!=0) {
    sprintf(output, "Error closing spectrum file %s", specfile);
    SCTPUT(output);
    return MAREMMA;
  }

  return NOERR;

}


static flames_err 
updatecheck_template(char *newtemplatefile, char *oldtemplatefile, 
		     specdescriptors *tempdescr) 
{

  char type=0;
  int noelem=0;
  int bytelem=0;
  int specid=0;
  char output[160];
  int actvals=0;
  int unit=0;
  int null=0;
  int ivecbuf[10];
  int i=0;
  specdescriptors *specdescr;

  memset(output, 0, 160);

  specdescr = (specdescriptors *) calloc(1, sizeof(specdescriptors));
  specdescr->npix = ivector(0,1);
  specdescr->start = dvector(0,1);
  specdescr->step = dvector(0,1);
  specdescr->cunit = calloc((size_t) 49, sizeof(char));
  specdescr->orderlim = ivector(0,1);
  specdescr->lhcuts = vector(0,3);
  specdescr->ident = calloc((size_t) 73, sizeof(char));
  if (tempdescr->nflats>0) specdescr->yshift = dvector(0,tempdescr->nflats);
  if (tempdescr->rebinflag==TRUE) {
    specdescr->rebinflag=TRUE;
    specdescr->wstart = dmatrix(0, tempdescr->maxfibres-1, 
				0, tempdescr->npix[1]-1);
    specdescr->nptot = imatrix(0, tempdescr->maxfibres-1, 
			       0, tempdescr->npix[1]-1);
    specdescr->norder = ivector(0,tempdescr->npix[1]-1);
  }
  else specdescr->rebinflag=FALSE;


  /* check dattype */
  if (SCFINF(newtemplatefile, 4, ivecbuf)!=0) {
    sprintf(output, "Error opening file %s", newtemplatefile);
    SCTPUT(output);
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  tempdescr->dattype = ivecbuf[1];
  /* open the spectrum */
  if (SCFOPN(newtemplatefile, tempdescr->dattype, 0, F_IMA_TYPE, &specid)!=0) {
    sprintf(output, "Error opening file %s", newtemplatefile);
    SCTPUT(output);
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  /* read the descriptors and compare them with the template */
  if ((SCDRDC(specid, "IDENT", 1, 1, 72, &actvals, tempdescr->ident, &unit, 
	      &null)!=0) || (actvals!=72)) {
    sprintf(output, "Error reading IDENT from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDI(specid, "NAXIS", 1, 1, &actvals, &specdescr->naxis, &unit, 
	      &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading NAXIS from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (specdescr->naxis != tempdescr->naxis) {
    sprintf(output, "Error: wrong NAXIS in file %s",
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (SCDFND(specid, "YSHIFT", &type, &noelem, &bytelem)!=0) {
    sprintf(output, "Error looking for descriptor YSHIFT in file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  switch(type) {
  case 'D':
    /* yshift is set and is of type double, use it */
    specdescr->nflats = noelem;
    break;
  case ' ':
    /* yshift is not set, hence nflats=0 */
    specdescr->nflats = 0;
    break;
  default:
    /* yshift is of the wrong type, set nflats to zero but issue a warning */
    specdescr->nflats = 0;
    sprintf(output, "Warning: wrong descriptor type for YSHIFT in %s", 
	    newtemplatefile);
    SCTPUT(output);
    break;
  }
  if (specdescr->nflats != tempdescr->nflats) {
    sprintf(output, "Error: YSHIFT size mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (tempdescr->nflats>0) {
    if ((SCDRDD(specid, "YSHIFT", 1, specdescr->nflats, &actvals, 
		specdescr->yshift, &unit, &null)!=0) || 
	(actvals!=specdescr->nflats)) {
      sprintf(output, "Error reading YSHIFT from file %s", 
	      newtemplatefile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing spectrum file %s", newtemplatefile);
	SCTPUT(output);
      }
      free_specdescriptors(specdescr);
      free(specdescr);
      return MAREMMA;
    }
    for (i=0; i<=(specdescr->nflats-1); i++) {
      if (specdescr->yshift[i] != tempdescr->yshift[i]) {
	sprintf(output, "Error: YSHIFT mismatch between files %s and %s",
		newtemplatefile, oldtemplatefile);
	SCTPUT(output);
	if (SCFCLO(specid)!=0) {
	  sprintf(output, "Error closing spectrum file %s", newtemplatefile);
	  SCTPUT(output);
	}
	free_specdescriptors(specdescr);
	free(specdescr);
	return MAREMMA;
      }
    }
  }
  if ((SCDRDI(specid, "NPIX", 1, 2, &actvals, specdescr->npix, &unit, 
	      &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading NPIX from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((specdescr->npix[0] > tempdescr->npix[0]) || 
      (specdescr->npix[1] != tempdescr->npix[1])) {
    sprintf(output, "Error: NPIX mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDD(specid, "START", 1, 2, &actvals, specdescr->start, &unit, 
	      &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading START from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((specdescr->start[0] != tempdescr->start[0]) || 
      (specdescr->start[1] != tempdescr->start[1])) {
    sprintf(output, "Error: START mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDD(specid, "STEP", 1, 2, &actvals, specdescr->step, &unit, 
	      &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading STEP from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((specdescr->step[0] != tempdescr->step[0]) || 
      (specdescr->step[1] != tempdescr->step[1])) {
    sprintf(output, "Error: STEP mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDC(specid, "CUNIT", 1, 1, 48, &actvals, specdescr->cunit, &unit, 
	      &null)!=0) || (actvals!=48)) {
    sprintf(output, "Error reading CUNIT from spectrum file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (strncmp(specdescr->cunit, tempdescr->cunit, 48)!=0) {
    sprintf(output, "Error: CUNIT mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDI(specid, "MAXFIBRES", 1, 1, &actvals, &specdescr->maxfibres, 
	      &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading MAXFIBRES from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (specdescr->maxfibres != tempdescr->maxfibres) {
    sprintf(output, "Error: MAXFIBRES mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDC(specid, "CHIPCHOICE", 1, 1, 1, &actvals, 
	      &specdescr->chipchoice, &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading CHIPCHOICE from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (specdescr->chipchoice != tempdescr->chipchoice) {
    sprintf(output, "Error: CHIPCHOICE mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDD(specid, "RON", 1, 1, &actvals, &specdescr->ron, &unit, 
	      &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading RON from file %s", newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (specdescr->ron != tempdescr->ron) {
    sprintf(output, "Error: RON mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDD(specid, "GAIN", 1, 1, &actvals, &specdescr->gain, &unit, 
	      &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading GAIN from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (specdescr->gain != tempdescr->gain) {
    sprintf(output, "Error: GAIN mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDI(specid, "ORDERLIM", 1, 2, &actvals, specdescr->orderlim, 
	      &unit, &null)!=0) || (actvals!=2)) {
    sprintf(output, "Error reading ORDERLIM from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((specdescr->orderlim[0] != tempdescr->orderlim[0]) || 
      (specdescr->orderlim[1] != tempdescr->orderlim[1])) {
    sprintf(output, "Error: ORDERLIM mismatch between files %s and %s",
	    newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDI(specid, "TAB_IN_OUT_OSHIFT", 1, 1, &actvals, 
	      &specdescr->tab_io_oshift, &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading TAB_IN_OUT_OSHIFT from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if (specdescr->tab_io_oshift != tempdescr->tab_io_oshift) {
    sprintf(output, "Error: TAB_IN_OUT_OSHIFT mismatch between files %s \
and %s", newtemplatefile, oldtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  /* should WSTART, NPTOT and NORDER be defined? */
  if (tempdescr->rebinflag==TRUE) {
    if ((SCDRDI(specid, "NORDER", 1, tempdescr->npix[1], &actvals, 
		specdescr->norder, &unit, &null)!=0) || 
	(actvals!=tempdescr->npix[1])) {
      sprintf(output, "Error reading NORDER from file %s", 
	      newtemplatefile);
      SCTPUT(output);
      if (SCFCLO(specid)!=0) {
	sprintf(output, "Error closing file %s", newtemplatefile);
	SCTPUT(output);
      }
      free_specdescriptors(specdescr);
      free(specdescr);
      return MAREMMA;
    }
    for (i=0; i<=(specdescr->npix[1]-1); i++) {
      if (specdescr->norder[i] != tempdescr->norder[i]) {
	sprintf(output, "Error: NORDER mismatch between files %s and %s",
		newtemplatefile, oldtemplatefile);
	SCTPUT(output);
	if (SCFCLO(specid)!=0) {
	  sprintf(output, "Error closing file %s", newtemplatefile);
	  SCTPUT(output);
	}
	free_specdescriptors(specdescr);
	free(specdescr);
	return MAREMMA;
      }
    }
  }
  /* now read descriptors which must be present but need not be compared
     with a template */
  if ((SCDRDR(specid, "LHCUTS", 1, 4, &actvals, specdescr->lhcuts, &unit, 
	      &null)!=0) || (actvals!=4)) {
    sprintf(output, "Error reading LHCUTS from file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  if ((SCDRDI(specid, "FIBRENUM", 1, 1, &actvals, &specdescr->fibrenum, 
	      &unit, &null)!=0) || (actvals!=1)) {
    sprintf(output, "Error reading FIBRENUM from spectrum file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }
  /* check fibrenum */
  if ((specdescr->fibrenum<1)||(specdescr->fibrenum>specdescr->maxfibres)) {
    sprintf(output, "Error: inconsistent FIBRENUM in file %s", 
	    newtemplatefile);
    SCTPUT(output);
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing spectrum file %s", newtemplatefile);
      SCTPUT(output);
    }
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }

  /* close file */
  if (SCFCLO(specid)!=0) {
    sprintf(output, "Error closing spectrum file %s", newtemplatefile);
    SCTPUT(output);
    free_specdescriptors(specdescr);
    free(specdescr);
    return MAREMMA;
  }

  free_specdescriptors(specdescr);
  free(specdescr);

  return NOERR;

}


static flames_err 
write_cube(char *cubename, specdescriptors *tempdescr, 
	   int *fibremask, char ***charcube)

{

  int cubeid=0;
  char output[160];
  int unit=0;
  int cnaxis=0;
  int cnpix[3];
  double cstart[3];
  double cstep[3];
  char cunit[65];
  frame_data ***speccube=0;
  frame_data *fdvecbuf1=0;
  int32_t cubemaxindex=0;
  float minimum=0;
  float maximum=0;
  int32_t i=0;
  float fbuf1=0;
  frame_mask ***maskcube=0;
  frame_mask *fmvecbuf1=0;
  float ***fmaskcube=0;
  float *fvecbuf1=0;
  float cuts[4];

  memset(output, 0, 160);
  memset(cunit, 0, 65);


  /* first, create the file which will hold the cube */
  if (SCFCRE(cubename, tempdescr->dattype, F_O_MODE, F_IMA_TYPE, 
	     tempdescr->maxfibres*tempdescr->npix[0]*tempdescr->npix[1], 
	     &cubeid)!=0) {
    sprintf(output, "Error creating cube file %s", cubename);
    SCTPUT(output);
    return MAREMMA;
  }
  /* then, begin writing descriptors */
  if (SCDWRC(cubeid, "IDENT", 1, tempdescr->ident, 1, 72, &unit)) {
    sprintf(output, "Error writing IDENT to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return MAREMMA;
  }
  cnaxis = 3;
  if (SCDWRI(cubeid, "NAXIS", &cnaxis, 1, 1, &unit)) {
    sprintf(output, "Error writing NAXIS to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return MAREMMA;
  }
  cnpix[0] = tempdescr->npix[0];
  cnpix[1] = tempdescr->npix[1];
  cnpix[2] = tempdescr->maxfibres;
  if (SCDWRI(cubeid, "NPIX", cnpix, 1, 3, &unit)) {
    sprintf(output, "Error writing NPIX to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid);
    return MAREMMA;
  }
  cstart[0] = tempdescr->start[0];
  cstart[1] = tempdescr->start[1];
  cstart[2] = 1;
  if (SCDWRD(cubeid, "START", cstart, 1, 3, &unit)) {
    sprintf(output, "Error writing START to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return MAREMMA;
  }
  cstep[0] = tempdescr->step[0];
  cstep[1] = tempdescr->step[1];
  cstep[2] = 1;
  if (SCDWRD(cubeid, "STEP", cstep, 1, 3, &unit)) {
    sprintf(output, "Error writing STEP to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return MAREMMA;
  }
  memcpy(cunit, tempdescr->cunit, 48);
  memcpy(cunit+48, "FIBRE           ", 16);
  if (SCDWRC(cubeid, "CUNIT", 1, cunit, 1, 64, &unit)) {
    sprintf(output, "Error writing CUNIT to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return(MAREMMA);
  }
  if (tempdescr->dattype==FLAMESDATATYPE) {
    speccube = (frame_data ***) charcube;
    fdvecbuf1 = speccube[0][0];
    cubemaxindex = (tempdescr->maxfibres*tempdescr->npix[0]*
		    tempdescr->npix[1])-1;
    minimum = maximum = (float) fdvecbuf1[0];
    for (i=1; i<=cubemaxindex; i++) {
      fbuf1 = (float) fdvecbuf1[i];
      if (fbuf1<minimum) minimum = fbuf1;
      if (fbuf1>maximum) maximum = fbuf1;
    }
  }
  else if (tempdescr->dattype==FLAMESMASKTYPE) {
    maskcube = (frame_mask ***) charcube;
    fmvecbuf1 = maskcube[0][0];
    cubemaxindex = (tempdescr->maxfibres*tempdescr->npix[0]*
		    tempdescr->npix[1])-1;
    minimum = maximum = (float) fmvecbuf1[0];
    for (i=1; i<=cubemaxindex; i++) {
      fbuf1 = (float) fmvecbuf1[i];
      if (fbuf1<minimum) minimum = fbuf1;
      if (fbuf1>maximum) maximum = fbuf1;
    }
  }
  else if (tempdescr->dattype==D_R4_FORMAT) {
    fmaskcube = (float ***) charcube;
    fvecbuf1 = fmaskcube[0][0];
    cubemaxindex = (tempdescr->maxfibres*tempdescr->npix[0]*
		    tempdescr->npix[1])-1;
    minimum = maximum = fvecbuf1[0];
    for (i=1; i<=cubemaxindex; i++) {
      fbuf1 = fvecbuf1[i];
      if (fbuf1<minimum) minimum = fbuf1;
      if (fbuf1>maximum) maximum = fbuf1;
    }
  }
  else {
    /* we should never get here, but an additional check never hurts */
    SCTPUT("Error: unsupported dattype in write_cube()");
    return MAREMMA;
  }
  cuts[0] = cuts[1] = 0;
  cuts[2] = minimum;
  cuts[3] = maximum;
  if (SCDWRR(cubeid, "LHCUTS", cuts, 1, 4, &unit)) {
    sprintf(output, "Error writing LHCUTS to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid);
    return MAREMMA;
  }
  if (SCDWRI(cubeid, "MAXFIBRES", &tempdescr->maxfibres, 1, 1, &unit)) {
    sprintf(output, "Error writing MAXFIBRES to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return MAREMMA;
  }
  if (SCDWRC(cubeid, "CHIPCHOICE", 1, &tempdescr->chipchoice, 1, 1, &unit)) {
    sprintf(output, "Error writing CHIPCHOICE to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid);
    return MAREMMA;
  }
  if (SCDWRD(cubeid, "RON", &tempdescr->ron, 1, 1, &unit)) {
    sprintf(output, "Error writing RON to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return MAREMMA;
  }
  if (SCDWRD(cubeid, "GAIN", &tempdescr->gain, 1, 1, &unit)) {
    sprintf(output, "Error writing GAIN to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid); 
    return MAREMMA;
  }
  if (tempdescr->nflats > 0) {
    if (SCDWRD(cubeid, "YSHIFT", tempdescr->yshift, 1, tempdescr->nflats, 
	       &unit)) {
      sprintf(output, "Error writing YSHIFT to cube file %s", cubename);
      SCTPUT(output);
      SCFCLO(cubeid); 
      return MAREMMA;
    }
  }
  if (SCDWRI(cubeid, "ORDERLIM", tempdescr->orderlim, 1, 2, &unit)) {
    sprintf(output, "Error writing ORDERLIM to cube file %s", cubename);
    SCTPUT(output);
    SCFCLO(cubeid);
    return MAREMMA;
  }
  if (SCDWRI(cubeid, "TAB_IN_OUT_OSHIFT", &tempdescr->tab_io_oshift, 
	     1, 1, &unit)) {
    sprintf(output, "Error writing TAB_IN_OUT_OSHIFT to cube file %s", 
	    cubename);
    SCTPUT(output);
    SCFCLO(cubeid);
    return MAREMMA;
  }
  if (SCDWRI(cubeid, "FIBREMASK", fibremask, 1, tempdescr->maxfibres, &unit)) {
    sprintf(output, "Error writing FIBREMASK to cube file %s", 
	    cubename);
    SCTPUT(output);
    SCFCLO(cubeid);
    return MAREMMA;
  }
  if (tempdescr->rebinflag==TRUE) {
    if (SCDWRD(cubeid, "WSTART", tempdescr->wstart[0], 1, 
	       tempdescr->maxfibres*tempdescr->npix[1], &unit)!=0) {
      sprintf(output, "Error writing WSTART to cube file %s", 
	      cubename);
      SCTPUT(output);
      SCFCLO(cubeid);
      return MAREMMA;
    }
    if (SCDWRI(cubeid, "NPTOT", tempdescr->nptot[0], 1, 
	       tempdescr->maxfibres*tempdescr->npix[1], &unit)!=0) {
      sprintf(output, "Error writing NPTOT to cube file %s", 
	      cubename);
      SCTPUT(output);
      SCFCLO(cubeid);
      return MAREMMA;
    }
    if (SCDWRI(cubeid, "NORDER", tempdescr->norder, 1, tempdescr->npix[1], 
	       &unit)!=0) {
      sprintf(output, "Error writing NORDER to cube file %s", 
	      cubename);
      SCTPUT(output);
      SCFCLO(cubeid);
      return MAREMMA;
    }
  }

  /* write the cube itself */
  if (tempdescr->dattype==FLAMESDATATYPE) {
    if(SCFPUT(cubeid, 1, 
	      tempdescr->maxfibres*tempdescr->npix[0]*tempdescr->npix[1], 
	      (char *) fdvecbuf1)!=0) {
      sprintf(output, "Error writing actual data to cube file %s", 
	      cubename);
      SCTPUT(output);
      SCFCLO(cubeid);
      return MAREMMA;
    }
  }
  else if (tempdescr->dattype==FLAMESMASKTYPE) {
    if(SCFPUT(cubeid, 1, 
	      tempdescr->maxfibres*tempdescr->npix[0]*tempdescr->npix[1], 
	      (char *) fmvecbuf1)!=0) {
      sprintf(output, "Error writing actual data to cube file %s", 
	      cubename);
      SCTPUT(output);
      SCFCLO(cubeid);
      return MAREMMA;
    }
  }
  else if (tempdescr->dattype==D_R4_FORMAT) {
    if(SCFPUT(cubeid, 1, 
	      tempdescr->maxfibres*tempdescr->npix[0]*tempdescr->npix[1], 
	      (char *) fvecbuf1)!=0) {
      sprintf(output, "Error writing actual data to cube file %s", 
	      cubename);
      SCTPUT(output);
      SCFCLO(cubeid);
      return MAREMMA;
    }
  }
  else {
    SCTPUT("Error: unsupported dattype in write_cube()");
    SCFCLO(cubeid);
    return MAREMMA;
  }
  /* close the cube */
  if (SCFCLO(cubeid)!=0) {
    sprintf(output, "Error closing cube file %s", 
	    cubename);
    SCTPUT(output);
    return MAREMMA;
  }

  return NOERR;

}


static flames_err 
read_sigmask_names(char **specnames, int nspectra, 
		   char **sigmanames, char **masknames) 
{

  char type1=0;
  char type2=0;
  char type3=0;
  int noelem1=0;
  int noelem2=0;
  int noelem3=0;
  int bytelem=0;
  int i=0;
  int j=0;
  int specid=0;
  char output[160];
  int actvals=0;
  int sigmaid=0;
  int maskid=0;
  int specfibrenum=0;
  int sigmafibrenum=0;
  int maskfibrenum=0;
  int specnpix=0;
  int sigmanpix=0;
  int masknpix=0;
  int unit=0;
  int null=0;
  double *wstart1=0;
  double *wstart2=0;
  double *wstart3=0;
  int *nptot1=0;
  int *nptot2=0;
  int *nptot3=0;

  memset(output, 0, 160);

  for (i=0; i<=nspectra-1; i++) {
    if (SCFOPN(specnames[i], FLAMESDATATYPE, 0, F_IMA_TYPE, &specid)!=0) {
      sprintf(output, "Error opening spectrum file %s", specnames[i]);
      SCTPUT(output);
      return MAREMMA;
    }
    /* read the SIGMAFRAME and MASKFRAME descriptors */
    if ((SCDGETC(specid, "SIGMAFRAME", 1, 80, &actvals, sigmanames[i])!=0) ||
	(actvals<1)) {
      sprintf(output, "Error reading SIGMAFRAME from file %s", specnames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      return MAREMMA;
    }
    if ((SCDGETC(specid, "MASKFRAME", 1, 80, &actvals, masknames[i])!=0) ||
	(actvals<1)) {
      sprintf(output, "Error reading MASKFRAME from file %s", specnames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      return MAREMMA;
    }
    /* ok, try to open the sigma and mask frames */
    if (SCFOPN(sigmanames[i], FLAMESDATATYPE, 0, F_IMA_TYPE, &sigmaid)!=0) {
      sprintf(output, "Error opening sigma file %s", sigmanames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      return MAREMMA;
    }
    if (SCFOPN(masknames[i], FLAMESMASKTYPE, 0, F_IMA_TYPE, &maskid)!=0) {
      sprintf(output, "Error opening mask file %s", masknames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      return MAREMMA;
    }
    /* make sure that spectrum, sigma and mask file refer indeed to the same
       fibre */
    if ((SCDRDI(specid, "FIBRENUM", 1, 1, &actvals, &specfibrenum, &unit, 
		&null)!=0) || (actvals<1)) {
      sprintf(output, "Error reading FIBRENUM from file %s", specnames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if ((SCDRDI(sigmaid, "FIBRENUM", 1, 1, &actvals, &sigmafibrenum, &unit, 
		&null)!=0) || (actvals<1)) {
      sprintf(output, "Error reading FIBRENUM from file %s", sigmanames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if ((SCDRDI(maskid, "FIBRENUM", 1, 1, &actvals, &maskfibrenum, &unit, 
		&null)!=0) || (actvals<1)) {
      sprintf(output, "Error reading FIBRENUM from file %s", masknames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if (sigmafibrenum!=specfibrenum) {
      sprintf(output, "FIBRENUM mismatch between spectrum %s and sigma %s", 
	      specnames[i], sigmanames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if (maskfibrenum!=specfibrenum) {
      sprintf(output, "FIBRENUM mismatch between spectrum %s and mask %s", 
	      specnames[i], masknames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    /* make sure that corresponding spectrum, sigma and mask file have been 
       rebinned to the same NPIX value */
    if ((SCDRDI(specid, "NPIX", 1, 1, &actvals, &specnpix, &unit, 
		&null)!=0) || (actvals<1)) {
      sprintf(output, "Error reading NPIX from file %s", specnames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if ((SCDRDI(sigmaid, "NPIX", 1, 1, &actvals, &sigmanpix, &unit, 
		&null)!=0) || (actvals<1)) {
      sprintf(output, "Error reading NPIX from file %s", sigmanames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if ((SCDRDI(maskid, "NPIX", 1, 1, &actvals, &masknpix, &unit, 
		&null)!=0) || (actvals<1)) {
      sprintf(output, "Error reading NPIX from file %s", masknames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if (sigmanpix!=specnpix) {
      sprintf(output, "NPIX mismatch between spectrum %s and sigma %s", 
	      specnames[i], sigmanames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if (masknpix!=specnpix) {
      sprintf(output, "NPIX mismatch between spectrum %s and mask %s", 
	      specnames[i], masknames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    /* is this spectrum rebinned? look for WSTART, NPTOT and NORDER */
    if (SCDFND(specid, "WSTART", &type1, &noelem1, &bytelem)!=0) {
      sprintf(output, "Error searching WSTART from spectrum file %s", 
	      specnames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if (SCDFND(specid, "NPTOT", &type2, &noelem2, &bytelem)!=0) {
      sprintf(output, "Error searching NPTOT from spectrum file %s", 
	      specnames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    if (SCDFND(specid, "NORDER", &type3, &noelem3, &bytelem)!=0) {
      sprintf(output, "Error searching NORDER from spectrum file %s", 
	      specnames[i]);
      SCTPUT(output);
      SCFCLO(specid);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
      return MAREMMA;
    }
    /* what did I find? */
    if ((type1=='D') && (type2=='I') && (type3=='I') && 
	(noelem1==noelem2) && (noelem1==noelem3)) {
      /* this looks like a rebinned spectrum, set things up accordingly */
      wstart1 = dvector(0, noelem1-1);
      wstart2 = dvector(0, noelem2-1);
      wstart3 = dvector(0, noelem3-1);
      if ((SCDRDD(specid, "WSTART", 1, noelem1, &actvals, wstart1, &unit, 
		  &null)!=0) || (actvals!=noelem1)) {
	sprintf(output, "Error reading WSTART from file %s", specnames[i]);
	SCTPUT(output);
	free_dvector(wstart1, 0, noelem1-1);
	free_dvector(wstart2, 0, noelem2-1);
	free_dvector(wstart3, 0, noelem3-1);
	SCFCLO(specid);
	SCFCLO(sigmaid);
	SCFCLO(maskid);
	return MAREMMA;
      }
      if ((SCDRDD(sigmaid, "WSTART", 1, noelem2, &actvals, wstart2, &unit, 
		  &null)!=0) || (actvals!=noelem2)) {
	sprintf(output, "Error reading WSTART from file %s", sigmanames[i]);
	SCTPUT(output);
	free_dvector(wstart1, 0, noelem1-1);
	free_dvector(wstart2, 0, noelem2-1);
	free_dvector(wstart3, 0, noelem3-1);
	SCFCLO(specid);
	SCFCLO(sigmaid);
	SCFCLO(maskid);
	return MAREMMA;
      }
      if ((SCDRDD(maskid, "WSTART", 1, noelem3, &actvals, wstart3, &unit, 
		  &null)!=0) || (actvals!=noelem3)) {
	sprintf(output, "Error reading WSTART from file %s", masknames[i]);
	SCTPUT(output);
	free_dvector(wstart1, 0, noelem1-1);
	free_dvector(wstart2, 0, noelem2-1);
	free_dvector(wstart3, 0, noelem3-1);
	SCFCLO(specid);
	SCFCLO(sigmaid);
	SCFCLO(maskid);
	return MAREMMA;
      }
      for (j=0; j<=(noelem1-1); j++) {
	if (wstart2[j] != wstart1[j]) {
	  sprintf(output, "WSTART mismatch between spectrum %s and sigma %s", 
		  specnames[i], sigmanames[i]);
	  SCTPUT(output);
	  free_dvector(wstart1, 0, noelem1-1);
	  free_dvector(wstart2, 0, noelem2-1);
	  free_dvector(wstart3, 0, noelem3-1);
	  SCFCLO(specid);
	  SCFCLO(sigmaid);
	  SCFCLO(maskid);
	  return MAREMMA;
	}
	if (wstart3[j] != wstart1[j]) {
	  sprintf(output, "WSTART mismatch between spectrum %s and mask %s", 
		  specnames[i], masknames[i]);
	  SCTPUT(output);
	  free_dvector(wstart1, 0, noelem1-1);
	  free_dvector(wstart2, 0, noelem2-1);
	  free_dvector(wstart3, 0, noelem3-1);
	  SCFCLO(specid);
	  SCFCLO(sigmaid);
	  SCFCLO(maskid);
	  return MAREMMA;
	}
      }
      free_dvector(wstart1, 0, noelem1-1);
      free_dvector(wstart2, 0, noelem2-1);
      free_dvector(wstart3, 0, noelem3-1);
      nptot1 = ivector(0, noelem1-1);
      nptot2 = ivector(0, noelem2-1);
      nptot3 = ivector(0, noelem3-1);
      if ((SCDRDI(specid, "NPTOT", 1, noelem1, &actvals, nptot1, &unit, 
		  &null)!=0) || (actvals!=noelem1)) {
	sprintf(output, "Error reading NPTOT from file %s", specnames[i]);
	SCTPUT(output);
	free_ivector(nptot1, 0, noelem1-1);
	free_ivector(nptot2, 0, noelem2-1);
	free_ivector(nptot3, 0, noelem3-1);
	SCFCLO(specid);
	SCFCLO(sigmaid);
	SCFCLO(maskid);
	return MAREMMA;
      }
      if ((SCDRDI(sigmaid, "NPTOT", 1, noelem2, &actvals, nptot2, &unit, 
		  &null)!=0) || (actvals!=noelem2)) {
	sprintf(output, "Error reading NPTOT from file %s", sigmanames[i]);
	SCTPUT(output);
	free_ivector(nptot1, 0, noelem1-1);
	free_ivector(nptot2, 0, noelem2-1);
	free_ivector(nptot3, 0, noelem3-1);
	SCFCLO(specid);
	SCFCLO(sigmaid);
	SCFCLO(maskid);
	return MAREMMA;
      }
      if ((SCDRDI(maskid, "NPTOT", 1, noelem3, &actvals, nptot3, &unit, 
		  &null)!=0) || (actvals!=noelem3)) {
	sprintf(output, "Error reading NPTOT from file %s", masknames[i]);
	SCTPUT(output);
	free_ivector(nptot1, 0, noelem1-1);
	free_ivector(nptot2, 0, noelem2-1);
	free_ivector(nptot3, 0, noelem3-1);
	SCFCLO(specid);
	SCFCLO(sigmaid);
	SCFCLO(maskid);
	return MAREMMA;
      }
      for (j=0; j<=(noelem1-1); j++) {
	if (nptot2[j] != nptot1[j]) {
	  sprintf(output, "NPTOT mismatch between spectrum %s and sigma %s", 
		  specnames[i], sigmanames[i]);
	  SCTPUT(output);
	  free_ivector(nptot1, 0, noelem1-1);
	  free_ivector(nptot2, 0, noelem2-1);
	  free_ivector(nptot3, 0, noelem3-1);
	  SCFCLO(specid);
	  SCFCLO(sigmaid);
	  SCFCLO(maskid);
	  return MAREMMA;
	}
	if (nptot3[j] != nptot1[j]) {
	  sprintf(output, "NPTOT mismatch between spectrum %s and mask %s", 
		  specnames[i], masknames[i]);
	  SCTPUT(output);
	  free_ivector(nptot1, 0, noelem1-1);
	  free_ivector(nptot2, 0, noelem2-1);
	  free_ivector(nptot3, 0, noelem3-1);
	  SCFCLO(specid);
	  SCFCLO(sigmaid);
	  SCFCLO(maskid);
	  return MAREMMA;
	}
      }
      free_ivector(nptot1, 0, noelem1-1);
      free_ivector(nptot2, 0, noelem2-1);
      free_ivector(nptot3, 0, noelem3-1);
    }
    /* close all files */
    if (SCFCLO(specid)!=0) {
      sprintf(output, "Error closing file %s", specnames[i]);
      SCTPUT(output);
      SCFCLO(sigmaid);
      SCFCLO(maskid);
    }
    if (SCFCLO(sigmaid)!=0) {
      sprintf(output, "Error closing file %s", sigmanames[i]);
      SCTPUT(output);
      SCFCLO(maskid);
    }
    if (SCFCLO(maskid)!=0) {
      sprintf(output, "Error closing file %s", masknames[i]);
      SCTPUT(output);
    }
  }

  /* all names read, all FIBRENUMs agree, return */

  return NOERR;

}

/**
   @name  flames_cubify()  
   @short Coadd frames in cubes            
   @author G. Mulas  -  ITAL_FLAMES Consortium Ported to CPL by A. Modigliani                    
   @param INCAT   Input catalog 
   @param BASENAME Basename 
   @param CUBIFYALL Switch to cubify or not
   @param USEIDENT keyword to know whether to use the identifier to select 
   actual extracted spectra among catalog entries 


   @param SPECIDENT keyword to know the identifier to search to recognise 
   actual extracted spectra among catalog entries 

   Columns are created 
                                                                
   @return 0 if success

                                                                         
   DRS Functions called: none                                             
                                                                        
   Pseudocode:                                                            

   @note
*/


int 
flames_cubify(const cpl_frameset *INCAT,
	      const char *BASENAME,
	      const char *CUBIFYALL,
	      const char *USEIDENT,
	      const char *SPECIDENT)                  
{ 

  int actvals=0;
  int i=0;
  int nspectra=0;
  int entrynum=0;
  int dataid=0;
  int sigmaid=0;
  int maskid=0;
  int unit=0;
  const cpl_frameset *catname;
  char framename[CATREC_LEN+1];
  char basename[CATREC_LEN+1];
  char cubifyall[CATREC_LEN+1];
  char useident[CATREC_LEN+1];
  char specident[41];
  char filename[CATREC_LEN+1];
  char identifier[CATREC_LEN+1];
  char output[160];
  char cspecname[CATREC_LEN+5];
  char csigmaname[CATREC_LEN+5];
  char cmaskname[CATREC_LEN+5];
  char **specnames=0;
  char **sigmanames=0;
  char **masknames=0;
  specdescriptors *tempdescr=0;
  specdescriptors *specdescr=0;
  int *fibremask=0;
  frame_data ***speccube=0;
  frame_data ***sigmacube=0;
  frame_mask ***maskcube=0;
  float ***fmaskcube=0;
  char ***charcube=0;


  memset(framename, 0, CATREC_LEN+1);
  memset(basename, 0, CATREC_LEN+1);
  memset(cubifyall, 0, CATREC_LEN+1);
  memset(useident, 0, CATREC_LEN+1);
  memset(specident, 0, 41);
  memset(filename, 0, CATREC_LEN+1);
  memset(identifier, 0, CATREC_LEN+1);
  memset(output, 0, 160);
  memset(cspecname, 0, CATREC_LEN+5);
  memset(csigmaname, 0, CATREC_LEN+5);
  memset(cmaskname, 0, CATREC_LEN+5);

  /* enter the MIDAS environment */
  SCSPRO("cubify");

  /* read the INCAT keyword to know the name of the catalog file
     containing the list of extracted spectra */
  if (SCKGETC_fs(INCAT, 1, CATREC_LEN, &actvals, &catname)!=0) {
    /* the keyword seems undefined, protest... */
    return flames_midas_fail();
  }
  catname = INCAT;

  /* read the BASENAME keyword to know the name of the file
     containing the cubeified spectra */
  if (SCKGETC(BASENAME, 1, CATREC_LEN, &actvals, framename)!= 0) {
    /* the keyword seems undefined, protest... */
    return flames_midas_fail();
  }
  /* take away the extension, just in case */
  if (stripfitsext(framename, basename)!=NOERR) {
    sprintf(output, "Error stripping extension from %s", framename);
    SCTPUT(output);
    return flames_midas_fail();
  }

  /* read the CUBIFYALL keyword to know whether to automatically cubify also
     the variances and masks of extracted spectra */
  if (SCKGETC(CUBIFYALL, 1, CATREC_LEN, &actvals, cubifyall)!=0) {
    /* the keyword seems undefined, protest... */
    return flames_midas_fail();
  }
  /* is cubifyall at least 1 char long? */
  if (actvals>0) {
    /* convert cubifyall to all upper case */
    for (i=0; i<=(actvals-1); i++) cubifyall[i] = toupper(cubifyall[i]);
    /* compare cubifyall with YES/NO */
    if ((strncmp("YES", cubifyall, (size_t) actvals) != 0) &&
	(strncmp("NO", cubifyall, (size_t) actvals) != 0)) {
      SCTPUT("Warning: unsupported value for P3, falling back to Y");
      strcpy(cubifyall, "YES");
    }
  }
  else {
    /* P3 was empty, silently reset it to the default value */
    strcpy(cubifyall, "YES");
  }

  /* read the USEIDENT keyword to know whether to use the identifier
     to select actual extracted spectra among catalog entries */
  if (SCKGETC(USEIDENT, 1, CATREC_LEN, &actvals, useident)!=0) {
    /* the keyword seems undefined, protest... */
    return flames_midas_fail();
  }
  /* is useident at least 1 char long? */
  if (actvals>0) {
    /* convert useident to all upper case */
    for (i=0; i<=(actvals-1); i++) useident[i] = toupper(useident[i]);
    /* compare useident with YES/NO */
    if ((strncmp("YES", useident, (size_t) actvals) != 0) &&
	(strncmp("NO", useident, (size_t) actvals) != 0)) {
      SCTPUT("Warning: unsupported value for P4, falling back to N");
      strcpy(useident, "NO");
    }
  }
  else {
    /* P4 was empty, silently reset it to the default value */
    strcpy(useident, "NO");
  }

  /* read the SPECIDENT keyword to know the identifier to search
     to recognise actual extracted spectra among catalog entries */
  if (SCKGETC(SPECIDENT, 1, 40, &actvals, specident)!=0) {
    /* the keyword seems undefined, protest... */
    return flames_midas_fail();
  }
  /* if the specident string is shorter than 40 chars, pad it with spaces
     to make it exactly 40 chars long */
  for (i=actvals; i<=39; i++) specident[i] = ' ';
  /* terminate with a null character, just in case */
  specident[40] = '\0';

  /* (try to) count all frame names matching the requested ident, if any */
  nspectra = entrynum = 0;
  do {
    if (SCCGET(catname, 1 , filename, identifier, &entrynum)!=0) {
      /* error getting catalog entry */
      return flames_midas_fail();
    }
    /* did I get a valid catalog entry? */
    if ((filename[0]!=' ') && ((useident[0]=='N') || 
			       (strncmp(identifier, specident, 40)==0))) {
      nspectra++;
    }
  } while (filename[0] != ' ');
  /* were any matching spectra found? */
  if (nspectra == 0) {
    /* no spectra, complain and abort */
    SCTPUT("Error: no spectra found in supplied catalog");
    return flames_midas_fail();
  }
  /* allocate a string array for the names of spectra */
  specnames = (char **) calloc((size_t) nspectra, sizeof(char *));
  specnames[0] = (char *) calloc((size_t) (nspectra*(CATREC_LEN+1)), 
				 sizeof(char));
  for (i=1; i<=(nspectra-1); i++) specnames[i] = specnames[i-1]+CATREC_LEN+1;
  /* rerun over the catalog and put the names in specnames */
  i = entrynum = 0;
  do {
    if (SCCGET(catname,1,specnames[i],identifier,&entrynum)!=0) {
      /* error getting catalog entry */
      //      sprintf(output, "Error reading from catalog %s", catname);
      sprintf(output, "Error reading from catalog");
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      return flames_midas_fail();
    }
    /* did I get a valid catalog entry? */
    if ((specnames[i][0]!=' ') && ((useident[0]=='N') || 
				   (strncmp(identifier, specident, 40)==0))) {
      i++;
    }
  } while ((i<nspectra) && (specnames[i][0] != ' '));
  /* find out the dattype of the "spectra" */
  /* now, if automatic cubification of sigmas and masks is required, read
     the filenames of the sigmas and of the masks from SIGMAFRAME and MASKFRAME
     descriptors, and populate arrays of strings with their names */
  if (cubifyall[0]=='Y') {
    /* allocate string arrays for the names of sigmas and masks */
    sigmanames = (char **) calloc((size_t) nspectra, sizeof(char *));
    sigmanames[0] = (char *) calloc((size_t) (nspectra*(CATREC_LEN+1)), 
				    sizeof(char));
    masknames = (char **) calloc((size_t) nspectra, sizeof(char *));
    masknames[0] = (char *) calloc((size_t) (nspectra*(CATREC_LEN+1)), 
				   sizeof(char));
    for (i=1; i<=(nspectra-1); i++) {
      sigmanames[i] = sigmanames[i-1]+CATREC_LEN+1;
      masknames[i] = masknames[i-1]+CATREC_LEN+1;
    }

    /* read sigma and mask file names */
    if (read_sigmask_names(specnames, nspectra, sigmanames, masknames)!=NOERR){
      SCTPUT("Error reading sigma and mask file names from catalogs");
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      return flames_midas_fail();
    }
  }

  /* allocate tempdescr and static arrays in it */
  tempdescr = (specdescriptors *) calloc(1, sizeof(specdescriptors));
  tempdescr->npix = ivector(0,1);
  tempdescr->start = dvector(0,1);
  tempdescr->step = dvector(0,1);
  tempdescr->cunit = calloc((size_t) 49, sizeof(char));
  tempdescr->orderlim = ivector(0,1);
  tempdescr->lhcuts = vector(0,3);
  tempdescr->ident = calloc((size_t) 73, sizeof(char));
  tempdescr->rebinflag = FALSE;
  /* tempdescr->yshift cannot be allocated before reading tempdescr->nflats*/
  /* read descriptors from first spectrum as a template */
  if (read_desc_template(specnames, nspectra, tempdescr)!=NOERR) {
    sprintf(output, "Error reading descriptors from spectrum %s", 
	    specnames[0]);
    SCTPUT(output);
    free(specnames[0]);
    free(specnames);
    if (cubifyall[0]=='Y') {
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
    }
    free_specdescriptors(tempdescr);
    free(tempdescr);
    return flames_midas_fail();
  }

  /* is the dattype of the template file sensible? */
  if ((tempdescr->dattype!=FLAMESDATATYPE) && (cubifyall[0]=='Y')) {
    SCTPUT("Error: since automatic sigma and mask conversion was requested,");
    SCTPUT("the files selected in the input catalog _must_ be spectra,");
    sprintf(output, "but the dattype of file %s is wrong for a spectrum", 
	    specnames[0]);
    SCTPUT(output);
    free(specnames[0]);
    free(specnames);
    free(sigmanames[0]);
    free(sigmanames);
    free(masknames[0]);
    free(masknames);
    free_specdescriptors(tempdescr);
    free(tempdescr);
    return flames_midas_fail();
  }
  else if ((tempdescr->dattype!=FLAMESMASKTYPE) && 
	   (tempdescr->dattype!=D_R4_FORMAT)) {
    sprintf(output, "Error: unsupported dattype for file %s selected for \
cubification", specnames[0]);
    SCTPUT(output);
    free(specnames[0]);
    free(specnames);
    if (cubifyall[0]=='Y') {
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
    }
    free_specdescriptors(tempdescr);
    free(tempdescr);
    return flames_midas_fail();
  }

  /* allocate the cube, fibremask, specdescr */
  if (tempdescr->dattype==FLAMESDATATYPE) {
    speccube = fd3tensor(0, tempdescr->maxfibres-1, 0, tempdescr->npix[1]-1, 
			 0, tempdescr->npix[0]-1);
    charcube = (char ***) speccube;
  }
  else if (tempdescr->dattype==FLAMESMASKTYPE) {
    maskcube = fm3tensor(0, tempdescr->maxfibres-1, 0, tempdescr->npix[1]-1, 
			 0, tempdescr->npix[0]-1);
    charcube = (char ***) maskcube;
  }
  else if (tempdescr->dattype==D_R4_FORMAT) {
    fmaskcube = f3tensor(0, tempdescr->maxfibres-1, 0, tempdescr->npix[1]-1, 
			 0, tempdescr->npix[0]-1);
    charcube = (char ***) fmaskcube;
  }
  else {
    /* we should never arrive here, just be consistent and safe */
    sprintf(output, "Error: unsupported dattype for file %s selected for \
cubification", specnames[0]);
    SCTPUT(output);
    free(specnames[0]);
    free(specnames);
    if (cubifyall[0]=='Y') {
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
    }
    free_specdescriptors(tempdescr);
    free(tempdescr);
    return flames_midas_fail();
  }
  fibremask = ivector(0, tempdescr->maxfibres-1);
  specdescr = (specdescriptors *) calloc(1, sizeof(specdescriptors));
  specdescr->npix = ivector(0,1);
  specdescr->start = dvector(0,1);
  specdescr->step = dvector(0,1);
  specdescr->cunit = calloc((size_t) 49, sizeof(char));
  specdescr->orderlim = ivector(0,1);
  specdescr->lhcuts = vector(0,3);
  specdescr->ident = calloc((size_t) 73, sizeof(char));
  if (tempdescr->nflats>0) specdescr->yshift = dvector(0,tempdescr->nflats);
  if (tempdescr->rebinflag==TRUE) {
    specdescr->rebinflag=TRUE;
    specdescr->wstart = dmatrix(0, tempdescr->maxfibres-1, 
				0, tempdescr->npix[1]-1);
    specdescr->nptot = imatrix(0, tempdescr->maxfibres-1, 
			       0, tempdescr->npix[1]-1);
    specdescr->norder = ivector(0,tempdescr->npix[1]-1);
  }
  else specdescr->rebinflag=FALSE;

  /* ok, now we have a template for the common descriptors, read in all
     spectra, one by one */
  for (i=0; i<=(nspectra-1); i++) {
    /* check the i-th spectrum's descriptors against the template and, if all
       is well, read it into the appropriate layer of speccube */
    if (readcheck_spectrum(specnames[i], specdescr, specnames[0], tempdescr, 
			   charcube, fibremask)!=NOERR) {
      /* problems reading the spectrum, complain, clean up and exit */
      sprintf(output, "Error reading spectrum %s", specnames[i]);
      SCTPUT(output);
      /* insert freeing here */
      free(specnames[0]);
      free(specnames);
      if (cubifyall[0]=='Y') {
	free(sigmanames[0]);
	free(sigmanames);
	free(masknames[0]);
	free(masknames);
      }
      if (tempdescr->dattype==FLAMESDATATYPE) {
	free_fd3tensor(speccube, 0, tempdescr->maxfibres-1, 
		       0, tempdescr->npix[1]-1, 
		       0, tempdescr->npix[0]-1);
      }
      else if (tempdescr->dattype==FLAMESMASKTYPE) {
	free_fm3tensor(maskcube, 0, tempdescr->maxfibres-1, 
		       0, tempdescr->npix[1]-1, 
		       0, tempdescr->npix[0]-1);
      }
      else if (tempdescr->dattype==D_R4_FORMAT) {
	free_f3tensor(fmaskcube, 0, tempdescr->maxfibres-1, 
		      0, tempdescr->npix[1]-1, 
		      0, tempdescr->npix[0]-1);
      }
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
  }

  /* all spectra have been read, we can create the cube of spectra */
  sprintf(cspecname, "%s.fits", basename);
  if (write_cube(cspecname, tempdescr, fibremask, charcube)!=NOERR) {
    sprintf(output, "Error writing cube %s", cspecname);
    SCTPUT(output);
    free(specnames[0]);
    free(specnames);
    if (cubifyall[0]=='Y') {
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
    }
    if (tempdescr->dattype==FLAMESDATATYPE) {
      free_fd3tensor(speccube, 0, tempdescr->maxfibres-1, 
		     0, tempdescr->npix[1]-1, 
		     0, tempdescr->npix[0]-1);
    }
    else if (tempdescr->dattype==FLAMESMASKTYPE) {
      free_fm3tensor(maskcube, 0, tempdescr->maxfibres-1, 
		     0, tempdescr->npix[1]-1, 
		     0, tempdescr->npix[0]-1);
    }
    else if (tempdescr->dattype==D_R4_FORMAT) {
      free_f3tensor(fmaskcube, 0, tempdescr->maxfibres-1, 
		    0, tempdescr->npix[1]-1, 
		    0, tempdescr->npix[0]-1);
    }
    free_ivector(fibremask, 0, tempdescr->maxfibres-1);
    free_specdescriptors(specdescr);
    free(specdescr);
    free_specdescriptors(tempdescr);
    free(tempdescr);
    return flames_midas_fail();
  }

  /* free speccube, blank fibremask */
  if (tempdescr->dattype==FLAMESDATATYPE) {
    free_fd3tensor(speccube, 0, tempdescr->maxfibres-1, 
		   0, tempdescr->npix[1]-1, 
		   0, tempdescr->npix[0]-1);
  }
  else if (tempdescr->dattype==FLAMESMASKTYPE) {
    free_fm3tensor(maskcube, 0, tempdescr->maxfibres-1, 
		   0, tempdescr->npix[1]-1, 
		   0, tempdescr->npix[0]-1);
  }
  else if (tempdescr->dattype==D_R4_FORMAT) {
    free_f3tensor(fmaskcube, 0, tempdescr->maxfibres-1, 
		  0, tempdescr->npix[1]-1, 
		  0, tempdescr->npix[0]-1);
  }
  else {
    /* we should never arrive here, just be consistent and safe */
    sprintf(output, "Error: unsupported dattype for file %s selected for \
cubification", specnames[0]);
    SCTPUT(output);
    free(specnames[0]);
    free(specnames);
    if (cubifyall[0]=='Y') {
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
    }
    free_ivector(fibremask, 0, tempdescr->maxfibres-1);
    free_specdescriptors(specdescr);
    free(specdescr);
    free_specdescriptors(tempdescr);
    free(tempdescr);
    return flames_midas_fail();
  }
  for (i=0; i<=(tempdescr->maxfibres-1); i++) fibremask[i]=FALSE;

  /* if automatic conversion of sigmas and masks was requested, do it here */
  if (cubifyall[0]=='Y') {
    /* read the template for sigmas */
    if (updatecheck_template(sigmanames[0], specnames[0], tempdescr)!=NOERR) {
      sprintf(output, "Error reading template descriptors from file %s", 
	      sigmanames[0]);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* the dattype of a sigma file must be FLAMESDATATYPE */
    if (tempdescr->dattype != FLAMESDATATYPE) {
      sprintf(output, "Error: wrong dattype for sigma file %s", sigmanames[0]);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* allocate sigmacube */
    sigmacube = fd3tensor(0, tempdescr->maxfibres-1, 0, tempdescr->npix[1]-1, 
			  0, tempdescr->npix[0]-1);
    charcube = (char ***) sigmacube;
    /* read in all sigmas, one by one */
    for (i=0; i<=(nspectra-1); i++) {
      /* check the i-th sigma's descriptors against the template and, if all
	 is well, read it into the appropriate layer of sigmacube */
      if (readcheck_spectrum(sigmanames[i], specdescr, sigmanames[0], 
			     tempdescr, charcube, fibremask)!=NOERR) {
	/* problems reading the sigma, complain, clean up and exit */
	sprintf(output, "Error reading sigma file %s", sigmanames[i]);
	SCTPUT(output);
	free(specnames[0]);
	free(specnames);
	free(sigmanames[0]);
	free(sigmanames);
	free(masknames[0]);
	free(masknames);
	free_fd3tensor(sigmacube, 0, tempdescr->maxfibres-1, 
		       0, tempdescr->npix[1]-1, 
		       0, tempdescr->npix[0]-1);
	free_ivector(fibremask, 0, tempdescr->maxfibres-1);
	free_specdescriptors(specdescr);
	free(specdescr);
	free_specdescriptors(tempdescr);
	free(tempdescr);
	return flames_midas_fail();
      }
    }
    /* all sigmas have been read, we can create the cube of sigmas */
    sprintf(csigmaname, "%s_sigma.fits", basename);
    if (write_cube(csigmaname, tempdescr, fibremask, charcube)!=NOERR) {
      sprintf(output, "Error writing cube %s", csigmaname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_fd3tensor(sigmacube, 0, tempdescr->maxfibres-1, 
		     0, tempdescr->npix[1]-1, 
		     0, tempdescr->npix[0]-1);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* free sigmacube, blank fibremask */
    free_fd3tensor(sigmacube, 0, tempdescr->maxfibres-1, 0, 
		   tempdescr->npix[1]-1, 0, tempdescr->npix[0]-1);
    for (i=0; i<=(tempdescr->maxfibres-1); i++) fibremask[i]=FALSE;
    /* read the template for masks */
    if (updatecheck_template(masknames[0], specnames[0], tempdescr)!=NOERR) {
      sprintf(output, "Error reading template descriptors from file %s", 
	      masknames[0]);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* is the dattype of the mask a supported one (i.e. either FLAMESMASKTYPE
       for unrebinned spectra or D_R4_FORMAT for rebinned spectra)? */
    if (tempdescr->dattype==FLAMESMASKTYPE) {
      /* this is an unrebinned spectrum */
      /* allocate maskcube */
      maskcube = fm3tensor(0, tempdescr->maxfibres-1, 0, tempdescr->npix[1]-1, 
			   0, tempdescr->npix[0]-1);
      charcube = (char ***) maskcube;
    }
    else if (tempdescr->dattype==D_R4_FORMAT) {
      /* this is a rebinned spectrum */
      /* allocate floatmaskcube */
      fmaskcube = f3tensor(0, tempdescr->maxfibres-1, 
			   0, tempdescr->npix[1]-1, 
			   0, tempdescr->npix[0]-1);
      charcube = (char ***) fmaskcube;
    }
    else {
      /* what is this? I don't know how to handle it! */
      sprintf(output, "Error: unsupported dattype for mask %s", masknames[0]);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* read in all masks, one by one */
    for (i=0; i<=(nspectra-1); i++) {
      /* check the i-th mask's descriptors against the template and, if all
	 is well, read it into the appropriate layer of sigmacube */
      if (readcheck_spectrum(masknames[i], specdescr, masknames[0], 
			     tempdescr, charcube, fibremask)!=NOERR) {
	/* problems reading the sigma, complain, clean up and exit */
	sprintf(output, "Error reading mask file %s", masknames[i]);
	SCTPUT(output);
	/* insert freeing here */
	free(specnames[0]);
	free(specnames);
	free(sigmanames[0]);
	free(sigmanames);
	free(masknames[0]);
	free(masknames);
	if (tempdescr->dattype==FLAMESMASKTYPE) {
	  free_fm3tensor(maskcube, 0, tempdescr->maxfibres-1, 
			 0, tempdescr->npix[1]-1, 
			 0, tempdescr->npix[0]-1);
	}
	else if (tempdescr->dattype==D_R4_FORMAT) {
	  free_f3tensor(fmaskcube, 0, tempdescr->maxfibres-1, 
			0, tempdescr->npix[1]-1, 
			0, tempdescr->npix[0]-1);
	}
	free_ivector(fibremask, 0, tempdescr->maxfibres-1);
	free_specdescriptors(specdescr);
	free(specdescr);
	free_specdescriptors(tempdescr);
	free(tempdescr);
	return flames_midas_fail();
      }
    }
    /* all masks have been read, we can create the cube of masks */
    sprintf(cmaskname, "%s_mask.fits", basename);
    if (write_cube(cmaskname, tempdescr, fibremask, charcube)!=NOERR) {
      sprintf(output, "Error writing mask cube %s", cmaskname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      if (tempdescr->dattype==FLAMESMASKTYPE) {
	free_fm3tensor(maskcube, 0, tempdescr->maxfibres-1, 
		       0, tempdescr->npix[1]-1, 
		       0, tempdescr->npix[0]-1);
      }
      else if (tempdescr->dattype==D_R4_FORMAT) {
	free_f3tensor(fmaskcube, 0, tempdescr->maxfibres-1, 
		      0, tempdescr->npix[1]-1, 
		      0, tempdescr->npix[0]-1);
      }
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* free maskcube */
    if (tempdescr->dattype==FLAMESMASKTYPE) {
      free_fm3tensor(maskcube, 0, tempdescr->maxfibres-1, 0, 
		     tempdescr->npix[1]-1, 0, tempdescr->npix[0]-1);
    }
    else if (tempdescr->dattype==D_R4_FORMAT) {
      free_f3tensor(fmaskcube, 0, tempdescr->maxfibres-1, 0, 
		    tempdescr->npix[1]-1, 0, tempdescr->npix[0]-1);
    }
    else {
      /* what is this? I don't know how to handle it! */
      sprintf(output, "Error: unsupported dattype for mask %s", masknames[0]);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }

    /* write SIGMAFRAME and MASKFRAME descriptors */
    if (SCFOPN(cspecname, FLAMESDATATYPE, 0, F_IMA_TYPE, &dataid)!=0) {
      sprintf(output, "Error opening file %s", cspecname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    if (SCDWRC(dataid, "SIGMAFRAME", 1, csigmaname, 1, 90, &unit)!=0) {
      sprintf(output, "Error writing SIGMAFRAME in file %s", cspecname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      if (SCFCLO(dataid)!=0) {
	sprintf(output, "Error closing file %s", cspecname);
	SCTPUT(output);
      }
      return flames_midas_fail();
    }
    if (SCDWRC(dataid, "MASKFRAME", 1, cmaskname, 1, 90, &unit)!=0) {
      sprintf(output, "Error writing SIGMAFRAME in file %s", cspecname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      if (SCFCLO(dataid)!=0) {
	sprintf(output, "Error closing file %s", cspecname);
	SCTPUT(output);
      }
      return flames_midas_fail();
    }
    if (SCFCLO(dataid)!=0) {
      sprintf(output, "Error closing file %s", cspecname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* write SCIENCEFRAME descriptors */
    if (SCFOPN(csigmaname, FLAMESDATATYPE, 0, F_IMA_TYPE, &sigmaid)!=0) {
      sprintf(output, "Error opening file %s", csigmaname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    if (SCDWRC(sigmaid, "SCIENCEFRAME", 1, cspecname, 1, 90, &unit)!=0) {
      sprintf(output, "Error writing SCIENCEFRAME in file %s", csigmaname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      if (SCFCLO(sigmaid)!=0) {
	sprintf(output, "Error closing file %s", csigmaname);
	SCTPUT(output);
      }
      return flames_midas_fail();
    }
    if (SCFCLO(sigmaid)!=0) {
      sprintf(output, "Error closing file %s", csigmaname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    /* tempdescr->dattype still contains the dattype of the masks */
    if (SCFOPN(cmaskname, tempdescr->dattype, 0, F_IMA_TYPE, &maskid)!=0) {
      sprintf(output, "Error opening file %s", cmaskname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
    if (SCDWRC(maskid, "SCIENCEFRAME", 1, cspecname, 1, 90, &unit)!=0) {
      sprintf(output, "Error writing SCIENCEFRAME in file %s", cmaskname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      if (SCFCLO(maskid)!=0) {
	sprintf(output, "Error closing file %s", cmaskname);
	SCTPUT(output);
      }
      return flames_midas_fail();
    }
    if (SCFCLO(maskid)!=0) {
      sprintf(output, "Error closing file %s", cmaskname);
      SCTPUT(output);
      free(specnames[0]);
      free(specnames);
      free(sigmanames[0]);
      free(sigmanames);
      free(masknames[0]);
      free(masknames);
      free_ivector(fibremask, 0, tempdescr->maxfibres-1);
      free_specdescriptors(specdescr);
      free(specdescr);
      free_specdescriptors(tempdescr);
      free(tempdescr);
      return flames_midas_fail();
    }
  }

  else {
    SCTPUT("Warning: no SCIENCEFRAME, SIGMAFRAME or MASKFRAME descriptors \
were set");
    SCTPUT("if you need them, you should set them manually");
  }

  /* free all dynamic arrays */
  free_ivector(fibremask, 0, tempdescr->maxfibres-1);

  free_specdescriptors(specdescr);
  free(specdescr);

  free_specdescriptors(tempdescr);
  free(tempdescr);

  free(specnames[0]);
  free(specnames);

  if (cubifyall[0]=='Y') {
    free(sigmanames[0]);
    free(sigmanames);
    free(masknames[0]);
    free(masknames);
  }

  return SCSEPI();

}
/**@}*/
