UVES Pipeline Reference Manual  5.4.0
flames_midas_def.c
1 
2 /* *
3  * This file is part of the ESO UVES Pipeline *
4  * Copyright (C) 2004,2005 European Southern Observatory *
5  * *
6  * This library is free software; you can redistribute it and/or modify *
7  * it under the terms of the GNU General Public License as published by *
8  * the Free Software Foundation; either version 2 of the License, or *
9  * (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License *
17  * along with this program; if not, write to the Free Software *
18  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA *
19  * */
20 
21 /*
22  * $Author: amodigli $
23  * $Date: 2013-02-12 10:59:25 $
24  * $Revision: 1.8 $
25  * $Name: not supported by cvs2svn $
26  *
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32 
33 /*----------------------------------------------------------------------------*/
53 /*----------------------------------------------------------------------------*/
54 
55 /*-----------------------------------------------------------------------------
56  Includes
57  -----------------------------------------------------------------------------*/
58 #include <flames_midas_def.h>
59 
60 #include <uves_utils_cpl.h>
61 #include <uves_dfs.h>
62 #include <uves_dump.h>
63 #include <uves_utils_wrappers.h>
64 #include <uves_error.h>
65 
66 #include <uves_msg.h>
67 #include <uves_pfits.h>
68 #include <uves_globals.h>
69 #include <assert.h>
70 
71 #include <fitsio.h>
72 #include <string.h>
73 #include <errno.h>
74 /*-----------------------------------------------------------------------------
75  Defines
76  -----------------------------------------------------------------------------*/
77 
78 #define MAX_OPEN 1024 /* Maximum number of open images/tables files */
79 
81 /*-----------------------------------------------------------------------------
82  Functions prototypes
83  -----------------------------------------------------------------------------*/
84 /*-----------------------------------------------------------------------------
85  Variables
86  -----------------------------------------------------------------------------*/
87 
88 struct frame
89 {
90  const char *filename; /* NULL: slot not used */
91 
92  bool is_image; /* Image or table? */
93  union {
94  struct {
95  cpl_image *image;
96  cpl_type type; /* CPL type of image (cannot store this in
97  the CPL image structure, because the image may
98  be logically open before it is actually loaded
99  into memory) */
100  int dtype; /* MIDAS image type */
101  } image;
102  struct {
103  cpl_table *table; /* The actual table columns *and* an
104  'internal' column "Select" to record
105  selections */
106  cpl_table *colnames;
107  int maxrow; /* Number of rows actually used
108  (maybe be less than rows allocated) */
109  } table;
110  } data;
111 
112  uves_propertylist *header; /* Primary header, also for tables.
113  NULL: not loaded (yet) */
114  bool need_to_save; /* Need to save to disk when closing? */
115 
116  /* Invariants:
117  if need_to_save, then image/table is != NULL
118  For images:
119  if image != NULL, then cpl_image_get_type(image) = type
120  For tables:
121  (table == NULL) == (colnames == NULL)
122  if table != NULL, then table.ncol-1 == colnames.nrow
123  if table != NULL, table has column "Select"
124  */
125 
126 };
127 
128 #define COLNAME "ColName"
129 
130 /* There are 3(!) different representations of FITS headers
131 
132  1. As seen by the FLAMES code, e.g.
133 
134  LHCUTS[3]...
135  LHCUTS[4]...
136  ORDERLIM[1]...
137  ORDERLIM[2]...
138  ESO OBS ID...
139 
140  2. CPL propertylist
141 
142  DATAMIN...
143  DATAMAX...
144  ORDERLIM = x
145  ORDERLIM = y
146  ESO OBS ID...
147 
148  3. The actual FITS file
149 
150  DATAMIN...
151  DATAMAX...
152  HISTORY ORDERLIM
153  HISTORY x y
154  HISTORY
155  HIERARCH ESO OBS ID...
156 
157 */
158 
159 struct frame frames[MAX_OPEN];
160 const char *current_caller = NULL;
161 
162 /*-----------------------------------------------------------------------------
163  Implementation
164  -----------------------------------------------------------------------------*/
165 /*----------------------------------------------------------------------------*/
178 /*----------------------------------------------------------------------------*/
179 
180 static bool invariant(int id)
181 {
182  struct frame *frm = &frames[id];
183 
184  if (frm->is_image)
185  {
186  return
187  (!frm->need_to_save || frm->data.image.image != NULL) &&
188  (frm->data.image.image == NULL
189  || cpl_image_get_type(frm->data.image.image) == frm->data.image.type);
190  }
191  else
192  {
193  return (!frm->need_to_save || frm->data.table.table != NULL)
194  &&
195  ((frm->data.table.table == NULL) == (frm->data.table.colnames == NULL))
196  &&
197  (frm->data.table.table == NULL ||
198  cpl_table_get_ncol(frm->data.table.table) - 1 ==
199  cpl_table_get_nrow(frm->data.table.colnames))
200  &&
201  (frm->data.table.table == NULL ||
202  cpl_table_has_column(frm->data.table.table, "Select"));
203 
204  }
205 }
206 /*----------------------------------------------------------------------------*/
211 /*----------------------------------------------------------------------------*/
212 static bool
214 {
215  return frames[id].filename != NULL;
216 }
217 
218 /*----------------------------------------------------------------------------*/
224 /*----------------------------------------------------------------------------*/
225 static void
226 frame_new_image(int id, const char *filename,
227  uves_propertylist *header,
228  bool need_to_save,
229  cpl_image *image,
230  cpl_type type,
231  int dtype)
232 {
233  if (strstr(filename, ".fits") == filename + strlen(filename) - 5) {
234  frames[id].filename = uves_sprintf("%s", filename);
235  }
236  else if (strstr(filename, ".bdf") == filename + strlen(filename) - 4) {
237  /* Replace .bdf -> .fits */
238  frames[id].filename = uves_sprintf("%sX", filename);
239  ((char *)frames[id].filename)[strlen(filename) - 3] = 'f';
240  ((char *)frames[id].filename)[strlen(filename) - 2] = 'i';
241  ((char *)frames[id].filename)[strlen(filename) - 1] = 't';
242  ((char *)frames[id].filename)[strlen(filename) - 0] = 's';
243  }
244  else {
245  frames[id].filename = uves_sprintf("%s.fits", filename);
246  }
247  frames[id].is_image = true;
248  frames[id].data.image.image = image;
249  frames[id].data.image.type = type;
250  frames[id].data.image.dtype = dtype;
251  frames[id].header = header;
252  frames[id].need_to_save = need_to_save;
253 
254  return;
255 }
256 /*----------------------------------------------------------------------------*/
262 /*----------------------------------------------------------------------------*/
263 static void
264 frame_new_table(int id, const char *filename,
265  uves_propertylist *header,
266  bool need_to_save,
267  cpl_table *table,
268  int maxrow,
269  cpl_table *colnames)
270 {
271  if (strstr(filename, ".fits") == filename + strlen(filename) - 5) {
272  frames[id].filename = uves_sprintf("%s", filename);
273  }
274  else if (strstr(filename, ".tfits") == filename + strlen(filename) - 6) {
275  frames[id].filename = uves_sprintf("%s", filename);
276  }
277  else if (strstr(filename, ".tbl") == filename + strlen(filename) - 4) {
278  /* Replace .tbl -> .fits */
279  frames[id].filename = uves_sprintf("%sX", filename);
280  ((char *)frames[id].filename)[strlen(filename) - 3] = 'f';
281  ((char *)frames[id].filename)[strlen(filename) - 2] = 'i';
282  ((char *)frames[id].filename)[strlen(filename) - 1] = 't';
283  ((char *)frames[id].filename)[strlen(filename) - 0] = 's';
284  } else {
285  frames[id].filename = uves_sprintf("%s.fits", filename);
286  }
287  frames[id].is_image = false;
288  frames[id].data.table.table = table;
289  if (table != NULL) {
290  cpl_table_new_column(table, "Select", CPL_TYPE_INT);
291  cpl_table_fill_column_window_int(table, "Select",
292  0, cpl_table_get_nrow(table),
293  1); /* initialize to all selected */
294  }
295  else {
296  /* Select column will be created when table is loaded from disk */
297  }
298  frames[id].data.table.maxrow = maxrow;
299  frames[id].data.table.colnames = colnames;
300  frames[id].header = header;
301  frames[id].need_to_save = need_to_save;
302  return;
303 }
304 
305 /*----------------------------------------------------------------------------*/
311 /*----------------------------------------------------------------------------*/
312 static void
313 frame_free(int id)
314 {
315  if (frame_is_open(id))
316  {
317  uves_free_string_const(&frames[id].filename);
318  if (frames[id].is_image)
319  {
320  uves_free_image(&frames[id].data.image.image);
321  }
322  else
323  {
324  uves_free_table(&frames[id].data.table.table);
325  uves_free_table(&frames[id].data.table.colnames);
326  }
327  uves_free_propertylist(&frames[id].header);
328  }
329 }
330 
331 /*----------------------------------------------------------------------------*/
337 /*----------------------------------------------------------------------------*/
338 static bool
339 is_special_midas_descr(const char *descr)
340 {
341  return
342  strcmp(descr, "NPIX") == 0 ||
343  strcmp(descr, "REFPIX") == 0 ||
344  strcmp(descr, "START") == 0 ||
345  strcmp(descr, "STEP") == 0 ||
346  strcmp(descr, "ROTA") == 0 ||
347  strcmp(descr, "CUNIT") == 0 ||
348  strcmp(descr, "IDENT") == 0 ||
349  strcmp(descr, "O_TIME") == 0 ||
350  strcmp(descr, "LHCUTS") == 0 ||
351  strcmp(descr, "O_POS") == 0;
352 }
353 
354 /*----------------------------------------------------------------------------*/
362 /*----------------------------------------------------------------------------*/
363 static const char *
364 convert_to_fits(const char *descr, int indx)
365 {
366  /* Special MIDAS keywords are:
367  (MIDAS manual volume A p. 7-5)
368  NAXISn -> NPIXn
369  CRPIXn -> REFPIXn
370  CRVALn -> STARTn
371  CDELTn -> STEPn
372  CROTAn -> ROTAn
373  BUNIT -> CUNIT(1)
374  CTYPEn -> CUNIT(n+1)
375  OBJECT -> IDENT
376  DATE_OBS -> O_TIME(1)
377 
378  LHCUTS(1), LHCUTS(2)
379  internal in MIDAS,
380  not converted
381  DATAMIN -> LHCUTS(3) (and convert double -> float)
382  DATAMAX -> LHCUTS(4)
383  EPOCH -> O_POS(3)
384  EQUINOX -> O_POS(3)
385  */
386 
387  const char *fits_descr = NULL;
388  if (strcmp(descr, "NPIX" ) == 0) fits_descr = uves_sprintf("NAXIS%d", indx);
389  else if (strcmp(descr, "REFPIX") == 0) assure( false, CPL_ERROR_UNSUPPORTED_MODE, "%s", descr);
390  else if (strcmp(descr, "START" ) == 0) fits_descr = uves_sprintf("CRVAL%d", indx);
391  else if (strcmp(descr, "STEP" ) == 0) fits_descr = uves_sprintf("CDELT%d", indx);
392  else if (strcmp(descr, "ROTA" ) == 0) assure( false, CPL_ERROR_UNSUPPORTED_MODE, "%s", descr);
393  else if (strcmp(descr, "CUNIT" ) == 0)
394  fits_descr = (indx == 1) ? uves_sprintf("BUNIT") : uves_sprintf("CTYPE%d", indx);
395  else if (strcmp(descr, "IDENT" ) == 0) fits_descr = uves_sprintf("OBJECT");
396  else if (strcmp(descr, "O_TIME") == 0) assure( false, CPL_ERROR_UNSUPPORTED_MODE, "%s", descr);
397  else if (strcmp(descr, "LHCUTS") == 0)
398  {
399  fits_descr =
400  (indx == 1) ? uves_sprintf("LHCUTS1") : /* For now, write these keywords for indx 1,2 */
401  (indx == 2) ? uves_sprintf("LHCUTS2") :
402  (indx == 3) ? uves_sprintf("DATAMIN") : uves_sprintf("DATAMAX");
403  }
404  else if (strcmp(descr, "O_POS" ) == 0) assure( false, CPL_ERROR_UNSUPPORTED_MODE, "%s", descr);
405 
406  if (fits_descr == NULL)
407  {
408  fits_descr = uves_sprintf("%s", descr);
409  }
410 
411  cleanup:
412  return fits_descr;
413 }
414 
415 /*----------------------------------------------------------------------------*/
440 /*----------------------------------------------------------------------------*/
441 static void
443 {
444  int plist_size, i;
445  const char *new_name = NULL;
446  char *v = NULL;
447  cpl_table *new_values = NULL;
448  cpl_property *new_prop = NULL;
449  uves_propertylist *result = NULL; /* Cannot change type of one property,
450  need to copy to new list */
451  result = uves_propertylist_new();
452 
453  plist_size = uves_propertylist_get_size(*header);
454  for (i = 0; i < plist_size; i++) {
455  cpl_property *p = uves_propertylist_get(*header, i);
456  const char *name = cpl_property_get_name(p);
457  int j;
458 
459  if (cpl_property_get_comment(p) != NULL &&
460  strcmp(cpl_property_get_comment(p), "PROCESSED") == 0) {
461  /* already processed, ignore */
462  }
463  else if ((strlen(name) > 8 && strncmp(name, "ESO ", 4) != 0)
464  ||
465  (cpl_property_get_comment(p) != NULL &&
466  strcmp(cpl_property_get_comment(p), "MIDAS_DESC") == 0)) {
467 
468  int n_prop;
469 
470  uves_free_string_const(&new_name);
471  switch (cpl_property_get_type(p)) {
472  case CPL_TYPE_STRING:
473  new_name = uves_sprintf("'%s','C'", name);
474  break;
475  case CPL_TYPE_INT:
476  new_name = uves_sprintf("'%s','I'", name);
477  break;
478  case CPL_TYPE_FLOAT:
479  new_name = uves_sprintf("'%s','R*4'", name);
480  break;
481  case CPL_TYPE_DOUBLE:
482  new_name = uves_sprintf("'%s','R*8'", name);
483  break;
484  default:
485  assure(false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me %s %s", name,
486  uves_tostring_cpl_type(cpl_property_get_type(p)));
487  break;
488  }
489 
490  uves_free_table(&new_values);
491  new_values = cpl_table_new(2);
492  cpl_table_new_column(new_values, "Val", CPL_TYPE_STRING);
493  n_prop = 0;
494 
495  /* And collect this and any subsequent properties with same name */
496  for (j = i; j < plist_size; j++) {
497  cpl_property *p2;
498 
499  check_nomsg( p2 = uves_propertylist_get(*header, j) );
500  if (strcmp(cpl_property_get_name(p2), name) == 0) {
501  uves_msg_debug("Found %s", name);
502 
503  /* Here, we would like to remove p2 from the list
504  in order not to process it again, but uves_propertylists
505  don't support that */
506  cpl_property_set_comment(p2, "PROCESSED");
507 
508  assure( cpl_property_get_type(p2) == cpl_property_get_type(p),
509  CPL_ERROR_TYPE_MISMATCH,
510  "Found property %s with type %s and with type %s",
511  name,
512  uves_tostring_cpl_type(cpl_property_get_type(p)),
513  uves_tostring_cpl_type(cpl_property_get_type(p2)));
514 
515  uves_free_string(&v);
516  switch (cpl_property_get_type(p2)) {
517  case CPL_TYPE_STRING:
518  if(strlen(cpl_property_get_string(p2)) > 0) {
519  v = uves_sprintf("%s", cpl_property_get_string(p2));
520  } else {
521  uves_msg_debug("Empty string descriptor");
522  v=cpl_malloc(1);
523  *v='\0';
524  }
525  break;
526  case CPL_TYPE_INT:
527  v = uves_sprintf("%d", cpl_property_get_int(p2));
528  break;
529  case CPL_TYPE_FLOAT:
530  v = uves_sprintf("%g", cpl_property_get_float(p2));
531  break;
532  case CPL_TYPE_DOUBLE:
533  v = uves_sprintf("%g", cpl_property_get_double(p2));
534  break;
535  default:
536  assure(false, CPL_ERROR_UNSUPPORTED_MODE,
537  "Implement me %s %s", name,
538  uves_tostring_cpl_type(cpl_property_get_type(p2)));
539  break;
540  }
541 
542 
543  assure(v != NULL, CPL_ERROR_UNSPECIFIED,"Allocation failure");
544  assure( strlen(v) <= 80 - strlen("HISTORY "),
545  CPL_ERROR_UNSUPPORTED_MODE,
546  "Value (%s) too long string",
547  v);
548 
549 
550 
551  /* Increase table size as necessary */
552  if (n_prop >= cpl_table_get_nrow(new_values))
553  {
554  cpl_table_set_size(new_values,
555  2*cpl_table_get_nrow(new_values));
556  }
557 
558  check_nomsg( cpl_table_set_string(new_values, "Val", n_prop, v) );
559  n_prop += 1;
560  }
561  }
562  cpl_table_set_size(new_values, n_prop);
563 
564  /* if (strcmp(name, "SIGMAFRAME") == 0) {
565  cpl_table_dump(new_values, 0, cpl_table_get_nrow(new_values), stderr);
566  uves_print_uves_propertylist(*header, 0, uves_propertylist_get_size(*header));
567  } */
568 
569  /* Convert to 1+n+1 HISTORY entries */
570  uves_propertylist_append_string(result, "HISTORY", new_name);
571  for (j = 0; j < cpl_table_get_nrow(new_values); j++)
572  {
573  uves_propertylist_append_string(result, "HISTORY",
574  cpl_table_get_string(new_values, "Val", j));
575  }
576  uves_propertylist_append_string(result, "HISTORY", "");
577 
578 
579  }
580  else {
581  uves_free_property(&new_prop);
582  new_prop = cpl_property_duplicate(p);
583  uves_propertylist_append_property(result, new_prop);
584  }
585 
586  }
587 
588  uves_free_propertylist(header);
589  *header = uves_propertylist_duplicate(result);
590 
591  cleanup:
592  uves_free_string_const(&new_name);
593  uves_free_string(&v);
594  uves_free_table(&new_values);
595  uves_free_property(&new_prop);
596  uves_free_propertylist(&result);
597  return;
598 }
599 
600 /*----------------------------------------------------------------------------*/
620 /*----------------------------------------------------------------------------*/
621 static uves_propertylist *
622 load_header(const char *filename,
623  int extension)
624 {
625  uves_propertylist *fitsheader = NULL;
626  uves_propertylist *result = NULL;
627  int plist_size, i;
628  const char *new_name = NULL;
629  const char *new_value = NULL;
630 
631  const char *desc_name = NULL;
632  const void *values = NULL;
633 
634  check( fitsheader = uves_propertylist_load(filename, extension),
635  "Could not load extension %d header from file %s", extension, filename);
636 
637  result = uves_propertylist_new();
638  plist_size = uves_propertylist_get_size(fitsheader);
639  for (i = 0; i < plist_size; i++) {
640  cpl_property *p = uves_propertylist_get(fitsheader, i);
641  const char *name = cpl_property_get_name(p);
642  bool convert_from_midas = false;
643 
644  if (strcmp(name, "HISTORY") == 0)
645  {
646  const char *value;
647 
648  if (cpl_property_get_type(p) == CPL_TYPE_STRING)
649  {
650  value = cpl_property_get_string(p);
651 
652  /* If a MIDAS descriptor is encoded here.
653  Must match "'.+'"
654  */
655  if ((int)strlen(value) >= 3 &&
656  value[0] == '\'' &&
657  strstr(value+2, "'") != NULL)
658  {
659  /* Get descriptor name. */
660  uves_free_string_const(&desc_name);
661  desc_name = cpl_strdup(value+1);
662  *(strstr(desc_name, "'")) = '\0';
663 
664  convert_from_midas = !is_special_midas_descr(desc_name);
665 
666  /* i.e. don't convert e.g
667  HISTORY 'LHCUTS'
668  */
669  }
670  }
671  else
672  {
673  uves_msg_warning("%s has HISTORY property of non-string type (%s)",
674  filename,
675  uves_tostring_cpl_type(cpl_property_get_type(p)));
676  }
677  }
678 
679  if (convert_from_midas) {
680  int length, j;
681  int ncards;
682  cpl_type type;
683 
684  uves_free(values); values = NULL;
685  check( values =
686  uves_read_midas_array(fitsheader, desc_name, &length, &type,
687  &ncards),
688  "Could not get values of HISTORY descriptor '%s'", desc_name);
689 
690  i += ncards-1;
691 
692  /* Create new properties */
693  for (j = 0; j < ((type == CPL_TYPE_STRING) ? 1 : length); j++) {
694 
695  uves_free_string_const(&new_name);
696  new_name = uves_sprintf("%s", desc_name);
697 
698  switch(type) {
699  case CPL_TYPE_INT:
700  uves_propertylist_append_c_int(result, new_name, ((int*)values)[j], "MIDAS_DESC");
701  break;
702  case CPL_TYPE_FLOAT:
703  uves_propertylist_append_c_float(result, new_name, ((float*)values)[j], "MIDAS_DESC");
704  break;
705  case CPL_TYPE_DOUBLE:
706  uves_propertylist_append_c_double(result, new_name, ((double*)values)[j], "MIDAS_DESC");
707  break;
708  case CPL_TYPE_STRING:
709  uves_propertylist_append_c_string(result, new_name, (char *)values, "MIDAS_DESC");
710  break;
711  default:
712  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
713  "Type is %s", uves_tostring_cpl_type(type));
714  }
715  }
716  }
717  else {
718  uves_propertylist_append_property(result, p);
719  }
720  }
721 
722  cleanup:
723  uves_free_string_const(&new_name);
724  uves_free_string_const(&new_value);
725  uves_free_string_const(&desc_name);
726  uves_free_propertylist(&fitsheader);
727  uves_free(values); values = NULL;
728  if (cpl_error_get_code() != CPL_ERROR_NONE)
729  {
730  uves_free_propertylist(&result);
731  }
732  return result;
733 
734 }
735 /*----------------------------------------------------------------------------*/
740 /*----------------------------------------------------------------------------*/
741 cpl_type
743 {
744  cpl_type type = CPL_TYPE_INVALID;
745 
746  switch(dtype) {
747  case D_OLD_FORMAT: type = CPL_TYPE_FLOAT; break;
748  case D_R4_FORMAT: type = CPL_TYPE_FLOAT; break;
749  case D_R8_FORMAT: type = CPL_TYPE_DOUBLE; break;
750  case D_I1_FORMAT: type = CPL_TYPE_INT; break;
751  case D_I2_FORMAT: type = CPL_TYPE_INT; break;
752  case D_I4_FORMAT: type = CPL_TYPE_INT; break;
753  default:
754  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me %d",
755  dtype);
756  break;
757  }
758 
759  cleanup:
760  return type;
761 }
762 /*----------------------------------------------------------------------------*/
770 /*----------------------------------------------------------------------------*/
771 
772 static void
774 {
775  int extension = 0; /* For tables and images */
776 
777  passure( invariant(id), " ");
778 
779  passure( frame_is_open(id), " ");
780 
781  if (frames[id].header == NULL)
782  {
783  /* Convert MIDAS HISTORY descriptors to internal format */
784  check( frames[id].header = load_header(frames[id].filename,
785  extension),
786  "Error loading header from %s", frames[id].filename);
787 
788  uves_msg_debug("Loaded %s header (%ld FITS cards)",
789  frames[id].filename,
790  uves_propertylist_get_size(frames[id].header));
791  }
792 
793  passure( invariant(id), " ");
794 
795  cleanup:
796  return;
797 }
798 
799 /*----------------------------------------------------------------------------*/
807 /*----------------------------------------------------------------------------*/
808 static void
809 set_column_format_unit_tnull(cpl_table *t, const uves_propertylist *theader)
810 {
811  const char *colname;
812 
813  int tfield; /* number of columns */
814  char *key_type = NULL;
815  char *key_form = NULL;
816  char *key_unit = NULL;
817  char *key_null = NULL;
818  char *val_type = NULL;
819  char *val_form = NULL;
820  char *val_unit = NULL;
821  int val_null;
822 
823  check_nomsg( tfield = uves_propertylist_get_int(theader, "TFIELDS"));
824 
825  for(colname = cpl_table_get_column_name(t);
826  colname != NULL;
827  colname = cpl_table_get_column_name(NULL)) {
828  bool found = false;
829  int i;
830  for (i = 1; i <= tfield && !found; i++) {
831  uves_free_string(&key_type);
832  uves_free_string(&key_form);
833  uves_free_string(&key_unit);
834  uves_free_string(&key_null);
835  uves_free_string(&val_type);
836  uves_free_string(&val_form);
837  uves_free_string(&val_unit);
838  key_type = uves_sprintf("TTYPE%d", i); /* column name */
839  key_form = uves_sprintf("TFORM%d", i);
840  key_unit = uves_sprintf("TUNIT%d", i);
841  key_null = uves_sprintf("TNULL%d", i);
842 
843  /* remove trailing blanks */
844  val_type = cpl_strdup(uves_propertylist_get_string(theader, key_type));
845  if (strlen(val_type) > 0) {
846  while (val_type[strlen(val_type)-1] == ' ') {
847  val_type[strlen(val_type)-1] = '\0';
848  }
849  }
850 
851  if (strcmp(val_type, colname) == 0) {
852  found = true;
853  if (uves_propertylist_contains(theader, key_form)) {
854  val_form = cpl_strdup(uves_propertylist_get_string(theader, key_form));
855  if (strlen(val_form) > 0) {
856  while (val_form[strlen(val_form)-1] == ' ') {
857  val_form[strlen(val_form)-1] = '\0';
858  }
859  }
860 
861  cpl_table_set_column_format(t, colname, val_form);
862  }
863  if (uves_propertylist_contains(theader, key_unit)) {
864  val_unit = cpl_strdup(uves_propertylist_get_string(theader, key_unit));
865  if (strlen(val_unit) > 0) {
866  while (val_unit[strlen(val_unit)-1] == ' ') {
867  val_unit[strlen(val_unit)-1] = '\0';
868  }
869  }
870 
871  cpl_table_set_column_unit(t, colname, val_unit);
872  }
873  else {
874  /* FLAMES C code expects the unit to be always non-NULL,
875  therefore set it to an empty string.
876 
877  This was guaranteed by CPL-3.x which always wrote
878  the TUNIT keyword when saving.
879 
880  But with CPL-4, the TUNIT keyword is not always present.
881  */
882  cpl_table_set_column_unit(t, colname, " ");
883  }
884 
885  if (cpl_table_get_column_type(t, colname) == CPL_TYPE_INT &&
886  uves_propertylist_contains(theader, key_null)) {
887  val_null = uves_propertylist_get_int(theader, key_null);
888 
889  cpl_table_fill_invalid_int(t, colname, val_null);
890  }
891  }
892  }
893  }
894 
895  cleanup:
896  uves_free_string(&key_type);
897  uves_free_string(&key_form);
898  uves_free_string(&key_unit);
899  uves_free_string(&key_null);
900  uves_free_string(&val_type);
901  uves_free_string(&val_form);
902  uves_free_string(&val_unit);
903  return;
904 }
905 
906 /*----------------------------------------------------------------------------*/
912 /*----------------------------------------------------------------------------*/
913 static void
914 load_frame(int id)
915 {
916  uves_propertylist *theader = NULL;
917  cpl_imagelist *ilist = NULL;
918  fitsfile *fptr = NULL;
919 
920  /* doesn't have to hold here: passure( invariant(id), " "); */
921  passure( frame_is_open(id), " ");
922 
923  if (frames[id].is_image) {
924  if (frames[id].data.image.image == NULL) {
925  long naxes[4];
926  long firstpixel[4] = {1, 1, 1, 1};
927  int naxis;
928  int fio_status = 0;
929 
930  uves_msg_debug("Loading image %s (type %s) to memory",
931  frames[id].filename,
932  uves_tostring_cpl_type(frames[id].data.image.type));
933 
934  /* Use CFITSIO. CPL doesn't handle 4d images */
935 
936  fits_open_file(&fptr, frames[id].filename, READONLY, &fio_status);
937 
938  assure( fio_status == 0, CPL_ERROR_FILE_IO,
939  "Failed to open %s for reading", frames[id].filename );
940 
941  /* Get the image dimension */
942  fits_get_img_dim(fptr, &naxis, &fio_status);
943  assure( naxis == 1 || naxis == 2 || naxis == 3 || naxis == 4,
944  CPL_ERROR_ILLEGAL_INPUT, "Illegal dimension: %d", naxis);
945 
946  /* Get the file size */
947  naxes[0] = 1;
948  naxes[1] = 1;
949  naxes[2] = 1;
950  naxes[3] = 1;
951  fits_get_img_size(fptr, naxis, naxes, &fio_status);
952  assure( fio_status == 0, CPL_ERROR_FILE_IO,
953  "Failed to get %s image size", frames[id].filename);
954 
955 
956  frames[id].data.image.image = cpl_image_new(naxes[0] * naxes[1] * naxes[2] * naxes[3], 1,
957  frames[id].data.image.type);
958 
959  switch(frames[id].data.image.type) {
960  case CPL_TYPE_DOUBLE:
961  fits_read_pix(fptr, TDOUBLE, firstpixel, naxes[0] * naxes[1] * naxes[2] * naxes[3],
962  NULL, cpl_image_get_data_double(frames[id].data.image.image),
963  NULL, &fio_status);
964  break;
965  case CPL_TYPE_FLOAT:
966  fits_read_pix(fptr, TFLOAT, firstpixel, naxes[0] * naxes[1] * naxes[2] * naxes[3],
967  NULL, cpl_image_get_data_float(frames[id].data.image.image),
968  NULL, &fio_status);
969  break;
970  case CPL_TYPE_INT:
971  fits_read_pix(fptr, TINT, firstpixel, naxes[0] * naxes[1] * naxes[2] * naxes[3],
972  NULL, cpl_image_get_data_int(frames[id].data.image.image),
973  NULL, &fio_status);
974  break;
975  default:
976  assure( false, CPL_ERROR_INVALID_TYPE,
977  "Illegal type %s", uves_tostring_cpl_type(frames[id].data.image.type));
978 
979  }
980 
981  fits_close_file(fptr, &fio_status) ;
982  assure( fio_status == 0, CPL_ERROR_FILE_IO,
983  "Failed to load image %s", frames[id].filename);
984 
985  }
986  }
987  else
988  {
989  if (frames[id].data.table.table == NULL)
990  {
991  int extension = 1;
992  int mark_invalid_values = 1; /* 1=yes */
993  const char *name;
994  int row;
995 
996  uves_msg_debug("Loading table %s to memory", frames[id].filename);
997 
998  check( frames[id].data.table.table =
999  cpl_table_load(frames[id].filename,
1000  extension,
1001  mark_invalid_values),
1002  "Error loading table from %s", frames[id].filename);
1003 
1004  if (!cpl_table_has_column(frames[id].data.table.table, "Select")) {
1005  cpl_table_new_column(frames[id].data.table.table, "Select",
1006  CPL_TYPE_INT);
1007  cpl_table_fill_column_window_int(
1008  frames[id].data.table.table, "Select",
1009  0, cpl_table_get_nrow(frames[id].data.table.table),
1010  1);
1011  }
1012 
1013  frames[id].data.table.maxrow = cpl_table_get_nrow(frames[id].data.table.table);
1014 
1015  check( theader = uves_propertylist_load(frames[id].filename, extension),
1016  "Error loading table header from %s", frames[id].filename);
1017 
1018  /* Assign numbers to columns */
1019  frames[id].data.table.colnames =
1020  cpl_table_new(cpl_table_get_ncol(frames[id].data.table.table) - 1);
1021  cpl_table_new_column(frames[id].data.table.colnames, COLNAME, CPL_TYPE_STRING);
1022 
1023  for(name = cpl_table_get_column_name(frames[id].data.table.table), row = 0;
1024  name != NULL;
1025  name = cpl_table_get_column_name(NULL)) {
1026  if (strcmp(name, "Select") != 0) {
1027  cpl_table_set_string(frames[id].data.table.colnames, COLNAME, row, name);
1028  row++;
1029  }
1030  }
1031 
1032  /* Workaround here: cpl_table_load ignores the table column
1033  units/formats and TNULL, so read + set those manually */
1034  check( set_column_format_unit_tnull(frames[id].data.table.table, theader),
1035  "Error loading table %s format/units", frames[id].filename);
1036  }
1037  }
1038 
1039  passure( invariant(id), " ");
1040 
1041  cleanup:
1042  uves_free_imagelist(&ilist);
1043  uves_free_propertylist(&theader);
1044  return;
1045 }
1046 
1047 /*----------------------------------------------------------------------------*/
1058 /*----------------------------------------------------------------------------*/
1059 static cpl_property **
1061  const char *descr,
1062  char type, int length,
1063  int nexist)
1064 {
1065  const char *fits_descr = NULL;
1066  const char *previous_descr = NULL;
1067  cpl_property **cards = NULL;
1068  int i;
1069  cpl_property *new_prop = NULL;
1070 
1071  passure( header != NULL, " ");
1072  assure( length >= 1, CPL_ERROR_ILLEGAL_INPUT, "Length = %d", length);
1073 
1074  cards = cpl_malloc((length+1) * sizeof(cpl_property *));
1075 
1076  if (nexist > 0)
1077  {
1078  i = 0;
1079  check( previous_descr = convert_to_fits(descr, i + nexist),
1080  "Could not convert %s to FITS", descr);
1081  }
1082  else
1083  {
1084  previous_descr = uves_sprintf("----");
1085  }
1086 
1087  for (i = 1; i <= length; i++)
1088  {
1089  const char *comment;
1090 
1091  uves_free_string_const(&fits_descr);
1092  check( fits_descr = convert_to_fits(descr, i + nexist),
1093  "Could not convert %s to FITS", descr);
1094 
1095  uves_msg_debug("Creating property %s (%d of %d, type = '%c')", fits_descr,
1096  nexist + i, nexist + length, type);
1097 
1098  if (strcmp(descr, fits_descr) == 0 &&
1099  strncmp(descr, "CTYPE", 5) != 0 &&
1100  strncmp(descr, "CDELT", 5) != 0 &&
1101  strncmp(descr, "CRVAL", 5) != 0 &&
1102  strncmp(descr, "CRPIX", 5) != 0 &&
1103  strncmp(descr, "ESO QC", 6) != 0 &&
1104  strcmp(descr, "BUNIT") != 0 &&
1105  strcmp(descr, "COLS") != 0 &&
1106  strcmp(descr, "ROWS") != 0 &&
1107  strcmp(descr, "PIXMAX") != 0 &&
1108  strcmp(descr, "STARTX") != 0 &&
1109  strcmp(descr, "STARTY") != 0 &&
1110  strcmp(descr, "STEPX") != 0 &&
1111  strcmp(descr, "STEPY") != 0 &&
1112  strcmp(descr, "YSHIFT") != 0 &&
1113  strcmp(descr, "DATAMIN") != 0 &&
1114  strcmp(descr, "DATAMAX") != 0 &&
1115  strcmp(descr, "NFLATS") != 0 &&
1116  strcmp(descr, "RON") != 0 &&
1117  strcmp(descr, "GAIN") != 0 &&
1118  strcmp(descr, "FIBRESON") != 0)
1119  {
1120  /* Then it is a MIDAS descriptor which must be
1121  stored in HISTORY keywords */
1122  comment = "MIDAS_DESC";
1123  }
1124  else {
1125  /* It is a descriptor recognized by the FITS format
1126  (such as NAXIS1), which should not be converted
1127  into HISTORY format */
1128  comment = NULL;
1129  }
1130 
1131 
1132  switch(type)
1133  {
1134  case 'I': uves_propertylist_append_c_int (header, fits_descr, 0, comment) ; break;
1135  case 'R': uves_propertylist_append_c_float (header, fits_descr, 0.0, comment); break;
1136  case 'C': uves_propertylist_append_c_string(header, fits_descr, "0", comment); break;
1137  case 'D': uves_propertylist_append_c_double(header, fits_descr, 0.0, comment); break;
1138  default: assure( false, CPL_ERROR_UNSUPPORTED_MODE, "%c", type); break;
1139  }
1140 
1141  /* If name changes with index, get the first occurence */
1142 
1143  cards[i-1] = uves_find_property(header,
1144  fits_descr,
1145  strcmp(fits_descr, previous_descr) != 0 ?
1146  0 : i-1 + nexist);
1147 
1148  passure( cards[i-1] != NULL, "%s %d %d", fits_descr, i-1, nexist);
1149 
1150  uves_free_string_const(&previous_descr);
1151  previous_descr = uves_sprintf("%s", fits_descr);
1152  }
1153 
1154  cards[length] = NULL;
1155 
1156  cleanup:
1157  uves_free_property(&new_prop);
1158  uves_free_string_const(&fits_descr);
1159  uves_free_string_const(&previous_descr);
1160  return cards;
1161 }
1162 
1163 /*----------------------------------------------------------------------------*/
1182 /*----------------------------------------------------------------------------*/
1183 static cpl_property **
1184 get_descr_info(int id, const char *descr,
1185  char *type, int *length, int *bytelem)
1186 {
1187 
1188 
1189  *bytelem=*bytelem; //to remove compilation warning: this is not used
1190 
1191  cpl_property **cards = NULL;
1192  cpl_type t;
1193  const char *fits_descr = NULL;
1194  const char *previous_fits_descr = NULL;
1195  *type = ' ';
1196 
1197  passure( invariant(id), " ");
1198 
1199  assure( frame_is_open(id), CPL_ERROR_ILLEGAL_INPUT,
1200  "Frame no. %d is not open", id);
1201 
1202  check( load_frame_header(id),
1203  "Could not load header of file %s", frames[id].filename);
1204 
1205  cards = cpl_calloc(1, sizeof(cpl_property *));
1206  assure_mem( cards );
1207 
1208  *length = 0;
1209  do {
1210  *length += 1;
1211  cards = cpl_realloc(cards, (*length)*sizeof(cpl_property *));
1212 
1213  uves_free_string_const(&previous_fits_descr);
1214  previous_fits_descr = uves_sprintf("%s", fits_descr != NULL ? fits_descr : "----");
1215 
1216  uves_free_string_const(&fits_descr);
1217  fits_descr = convert_to_fits(descr, *length);
1218 
1219  uves_msg_debug("Searching for %d. occurence of %s",
1220  strcmp(fits_descr, previous_fits_descr) == 0 ?
1221  *length : 1,
1222  fits_descr);
1223  //uves_msg_debug("prev=%s curr=%s",previous_fits_descr,fits_descr);
1224  cards[*length-1] =
1225  uves_find_property(frames[id].header,
1226  fits_descr,
1227  strcmp(fits_descr, previous_fits_descr) == 0 ?
1228  *length - 1 : 0);
1229  }
1230  while (cards[*length-1] != NULL);
1231 
1232  *length -= 1;
1233 
1234  if (cards[0] != NULL)
1235  {
1236  t = cpl_property_get_type(cards[0]);
1237 
1238  switch(t)
1239  {
1240  case CPL_TYPE_INT : *type = 'I'; break;
1241  case CPL_TYPE_FLOAT : *type = 'R'; break;
1242  case CPL_TYPE_STRING: *type = 'C'; break;
1243  case CPL_TYPE_DOUBLE: *type = 'D'; break;
1244  default: *type = ' '; break;
1245  }
1246 
1247  uves_msg_debug("Type is %c", *type);
1248  //AMO: Here the check on the length was *length == 1
1249  assure( *type != 'C' || *length <= 3, CPL_ERROR_UNSUPPORTED_MODE,
1250  "Cannot handle string array descriptor %s %s of length %d",
1251  descr, cpl_property_get_string(cards[0]),*length );
1252 
1253  if (*type == 'C')
1254  {
1255  //AMO: Here the check on the length was *length == 1
1256  passure( *length <= 3, "%d", *length );
1257  /* ... but we must return the string length,
1258  not the number of cards */
1259  *length = strlen(cpl_property_get_string(cards[0]));
1260  }
1261  }
1262  else
1263  {
1264  uves_msg_debug("%s not found", fits_descr);
1265  cpl_free(cards); cards = NULL;
1266  *length = 0;
1267  }
1268 
1269  passure( invariant(id), " ");
1270 
1271  cleanup:
1272  uves_free_string_const(&fits_descr);
1273  uves_free_string_const(&previous_fits_descr);
1274  if (cpl_error_get_code() != CPL_ERROR_NONE)
1275  {
1276  cpl_free(cards); cards = NULL;
1277  }
1278 
1279  return cards;
1280 }
1281 
1282 /*----------------------------------------------------------------------------*/
1292 /*----------------------------------------------------------------------------*/
1293 int flames_midas_scspro(const char *name)
1294 {
1295  int i;
1296 
1297  assure( current_caller == NULL, CPL_ERROR_ILLEGAL_INPUT,
1298  "MIDAS mode already running");
1299 
1300  uves_msg_debug("Initializing %s", name);
1301  current_caller = uves_sprintf("%s", name);
1302 
1303  assure( strcmp(name, "-1") != 0, CPL_ERROR_UNSUPPORTED_MODE,
1304  "Running outside MIDAS mode not supported");
1305 
1306  /* Reset all file handles */
1307  for (i = 0; i < MAX_OPEN; i++)
1308  {
1309  frames[i].filename = NULL;
1310  }
1311 
1312  cleanup:
1313  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1314 }
1315 
1316 /*----------------------------------------------------------------------------*/
1321 /*----------------------------------------------------------------------------*/
1322 
1324 {
1325  if (current_caller == NULL)
1326  {
1327  uves_msg_warning("MIDAS mode not running, "
1328  "nothing to stop");
1329  }
1330  else
1331  {
1332  /* Check for unallocated resources */
1333  int i;
1334  for (i = 0; i < MAX_OPEN; i++)
1335  {
1336  if (frame_is_open(i))
1337  {
1338  uves_msg_warning("%s: %s no. %d: %s not deallocated",
1339  current_caller,
1340  frames[i].is_image ? "Image" : "Table",
1341  i, frames[i].filename);
1342 
1343  frame_free(i);
1344  }
1345  }
1346 
1347  uves_msg_debug("Ending %s", current_caller);
1348  uves_free_string_const(&current_caller);
1349  }
1350 
1351  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1352 }
1353 
1354 /*----------------------------------------------------------------------------*/
1370 /*----------------------------------------------------------------------------*/
1371 int flames_midas_error_macro(const char *file, const char *function, int line,
1372  int status)
1373 {
1374  uves_msg_debug("%s:%s() execution failed at %s:%s():%d",
1375  current_caller != NULL ? current_caller : "???",
1376  function, file, function, line);
1377 
1378  return status;
1379 }
1380 
1381 /*----------------------------------------------------------------------------*/
1388 /*----------------------------------------------------------------------------*/
1389 
1390 int flames_midas_fail_macro(const char *file, const char *function, int line)
1391 {
1392  const char *f = cpl_strdup(current_caller != NULL ? current_caller : "???");
1393  uves_msg_error("%s execution failed. Exit from MIDAS mode", f);
1394 
1395  uves_msg_debug(" at %s:%s():%d", file, function, line);
1396 
1398 
1399  assure( false, CPL_ERROR_UNSPECIFIED, "%s failed", f);
1400 
1401  cleanup:
1402  uves_free_string_const(&f);
1403  return 1;
1404 }
1405 
1406 /*----------------------------------------------------------------------------*/
1416 /*----------------------------------------------------------------------------*/
1417 int flames_midas_sckwri(int *key, const int *values,
1418  int felem, int maxvals, int *unit)
1419 {
1420  int i;
1421  if (unit) {} //to remove compilation warning: this is not used
1422 
1423  assure_nomsg( key != NULL, CPL_ERROR_NULL_INPUT );
1424 
1425  uves_msg_debug("Writing %d elements to integer keyword", maxvals);
1426 
1427  for (i = 0; i < maxvals; i++) {
1428  key[(felem-1) + i] = values[i];
1429  }
1430 
1431  cleanup:
1432  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1433 }
1434 
1435 /*----------------------------------------------------------------------------*/
1445 /*----------------------------------------------------------------------------*/
1446 int flames_midas_sckwrd(double *key, const double *values,
1447  int felem, int maxvals, int *unit)
1448 {
1449  int i;
1450  if (unit) {} //to remove compilation warning: this is not used
1451 
1452  assure_nomsg( key != NULL, CPL_ERROR_NULL_INPUT );
1453 
1454  uves_msg_debug("Writing %d elements to double keyword", maxvals);
1455 
1456  for (i = 0; i < maxvals; i++) {
1457  key[(felem-1) + i] = values[i];
1458  }
1459 
1460  //fixme: is unit used? MIDAS doc. says it's unsupported
1461 
1462  cleanup:
1463  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1464 }
1465 
1466 
1467 /*----------------------------------------------------------------------------*/
1478 /*----------------------------------------------------------------------------*/
1479 int flames_midas_sckwrc(char *key, int noelem,
1480  const char *values, int felem, int maxvals, int *unit)
1481 {
1482  if (unit) {} //to remove compilation warning: this is not used
1483  assure_nomsg( noelem == 1, CPL_ERROR_UNSUPPORTED_MODE);
1484  //fixme: remove from interface if this is always the case
1485 
1486  uves_msg_debug("Writing %d elements to character keyword", maxvals);
1487 
1488  strncpy(key+(felem-1), values, maxvals);
1489 
1490  //fixme: is unit used?
1491  cleanup:
1492  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1493 }
1494 
1495 /*----------------------------------------------------------------------------*/
1506 /*----------------------------------------------------------------------------*/
1507 int flames_midas_sckgetc(const char *key,
1508  int felem, int maxvals,
1509  int *actvals, char *values)
1510 {
1511 
1512  assure_nomsg( key != NULL, CPL_ERROR_NULL_INPUT );
1513  assure_nomsg( values != NULL, CPL_ERROR_NULL_INPUT );
1514  assure_nomsg( actvals!= NULL, CPL_ERROR_NULL_INPUT );
1515 
1516  strncpy(values, key + (felem - 1), maxvals);
1517  values[strlen(key)+1] = '\0';
1518  *actvals = strlen(values);
1519 
1520  /*
1521  uves_msg_warning("Copy %s to %s",
1522  key, values);
1523 
1524  */
1525 
1526  cleanup:
1527  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1528 }
1529 
1530 /*----------------------------------------------------------------------------*/
1540 /*----------------------------------------------------------------------------*/
1541 int flames_midas_sckgetc_fs(const cpl_frameset *key,
1542  int felem, int maxvals,
1543  int *actvals, const cpl_frameset **values)
1544 {
1545  maxvals=maxvals; //to remove compilation warning: this is not used
1546  assure_nomsg( key != NULL, CPL_ERROR_NULL_INPUT );
1547  assure( felem == 1, CPL_ERROR_ILLEGAL_INPUT,
1548  "felem = %d", felem );
1549  assure_nomsg( actvals != NULL, CPL_ERROR_NULL_INPUT );
1550  assure_nomsg( values != NULL, CPL_ERROR_NULL_INPUT );
1551 
1552  *values = key;
1553 
1554  cleanup:
1555  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1556 }
1557 
1558 /*----------------------------------------------------------------------------*/
1568 /*----------------------------------------------------------------------------*/
1569 int flames_midas_sckgetc_fsp(cpl_frameset **key,
1570  int felem, int maxvals,
1571  int *actvals, cpl_frameset ***values)
1572 {
1573  maxvals=maxvals; //to remove compilation warning: this is not used
1574  assure_nomsg( key != NULL, CPL_ERROR_NULL_INPUT );
1575  assure( felem == 1, CPL_ERROR_ILLEGAL_INPUT,
1576  "felem = %d", felem );
1577  assure_nomsg( actvals != NULL, CPL_ERROR_NULL_INPUT );
1578  assure_nomsg( values != NULL, CPL_ERROR_NULL_INPUT );
1579 
1580  *values = key;
1581 
1582  cleanup:
1583  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1584 }
1585 
1586 /*----------------------------------------------------------------------------*/
1598 /*----------------------------------------------------------------------------*/
1599 int flames_midas_sckrdd(const double *key, int felem, int maxvals,
1600  int *actvals, double *values, int *unit, int *null)
1601 {
1602  int i;
1603  if (unit) {} //to remove compilation warning: this is not used
1604  if (null) {} //to remove compilation warning: this is not used
1605 
1606  assure_nomsg( key != NULL, CPL_ERROR_NULL_INPUT );
1607 
1608  *actvals = 0;
1609  for (i = 0; i < maxvals; i++)
1610  {
1611  values[i] = key[(felem-1)+i];
1612  (*actvals)++;
1613  }
1614 
1615  /* unit, null not implemented in MIDAS */
1616 
1617  cleanup:
1618  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1619 }
1620 
1621 /*----------------------------------------------------------------------------*/
1633 /*----------------------------------------------------------------------------*/
1634 int flames_midas_sckrdr(const float *key, int felem, int maxvals,
1635  int *actvals, float *values, int *unit, int *null)
1636 {
1637  int i;
1638  if (unit) {} //to remove compilation warning: this is not used
1639  if (null) {} //to remove compilation warning: this is not used
1640 
1641  assure_nomsg( key != NULL, CPL_ERROR_NULL_INPUT );
1642 
1643  *actvals = 0;
1644  for (i = 0; i < maxvals; i++)
1645  {
1646  values[i] = key[(felem-1)+i];
1647  (*actvals)++;
1648  }
1649 
1650  /* unit, null not implemented in MIDAS */
1651 
1652  cleanup:
1653  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1654 }
1655 
1656 /*----------------------------------------------------------------------------*/
1668 /*----------------------------------------------------------------------------*/
1669 int flames_midas_sckrdi(const int *key, int felem, int maxvals,
1670  int *actvals, int *values, int *unit, int *null)
1671 {
1672  int i;
1673  if (unit) {} //to remove compilation warning: this is not used
1674  if (null) {} //to remove compilation warning: this is not used
1675 
1676  *actvals = 0;
1677  for (i = 0; i < maxvals; i++)
1678  {
1679  values[i] = key[(felem-1)+i];
1680  (*actvals)++;
1681  }
1682 
1683  /* unit, null not implemented in MIDAS */
1684 
1685 /* cleanup: */
1686  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1687 }
1688 
1689 /*----------------------------------------------------------------------------*/
1702 /*----------------------------------------------------------------------------*/
1703 int flames_midas_sckrdc(const char *key, int noelm, int felem, int maxvals,
1704  int *actvals, char *values, int *unit, int *null)
1705 {
1706  /* This function is only used in calls, like this
1707 
1708  SCKRDC("H_RON_L",16,1,1,&actvals, h_ron_l, &unit, &null)
1709 
1710  where noelm is the string length and felem = maxvals = 1 */
1711  if (unit) {} //to remove compilation warning: this is not used
1712  if (null) {} //to remove compilation warning: this is not used
1713 
1714  assure( felem == 1, CPL_ERROR_UNSUPPORTED_MODE, "Implement me" );
1715  assure( maxvals == 1, CPL_ERROR_UNSUPPORTED_MODE, "Implement me" );
1716 
1717  strncpy(values, key + (felem - 1), noelm);
1718  values[noelm] = '\0';
1719  *actvals = strlen(values);
1720 
1721  /* unit, null not implemented in MIDAS */
1722 
1723  cleanup:
1724  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1725 }
1726 
1727 /*----------------------------------------------------------------------------*/
1738 /*----------------------------------------------------------------------------*/
1739 static int
1740 sckfnd(const char the_type, const void *key, char *type, int *noelem, int *bytelem)
1741 {
1742  *noelem=*noelem; //to remove compilation warning: this is not used
1743  *bytelem=*bytelem; //to remove compilation warning: this is not used
1744  if (key == NULL)
1745  {
1746  uves_msg_debug("Keyword is NULL");
1747  *type = ' ';
1748  }
1749  else
1750  {
1751  *type = the_type;
1752  }
1753  /* Fixme: what about noelem (needs to be passed from the caller) */
1754 
1755 // cleanup:
1756  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1757 }
1758 
1759 /*----------------------------------------------------------------------------*/
1763 /*----------------------------------------------------------------------------*/
1764 int flames_midas_sckfnd_double(const double *key, char *type, int *noelem, int *bytelem)
1765 {
1766  return sckfnd('D', key, type, noelem, bytelem);
1767 }
1768 /*----------------------------------------------------------------------------*/
1772 /*----------------------------------------------------------------------------*/
1773 int flames_midas_sckfnd_float(const float *key, char *type, int *noelem, int *bytelem)
1774 {
1775  return sckfnd('R', key, type, noelem, bytelem);
1776 }
1777 
1778 /*----------------------------------------------------------------------------*/
1782 /*----------------------------------------------------------------------------*/
1783 int flames_midas_sckfnd_int(const int *key, char *type, int *noelem, int *bytelem)
1784 {
1785  return sckfnd('I', key, type, noelem, bytelem);
1786 }
1787 
1788 /*----------------------------------------------------------------------------*/
1792 /*----------------------------------------------------------------------------*/
1793 int flames_midas_sckfnd_string(const char *key, char *type, int *noelem, int *bytelem)
1794 {
1795  return sckfnd('C', key, type, noelem, bytelem);
1796 }
1797 
1798 /*----------------------------------------------------------------------------*/
1804 /*----------------------------------------------------------------------------*/
1805 
1806 int flames_midas_sctput(const char *msg,
1807  const char *function, const char *file, int line)
1808 {
1809  if (strncmp(msg, "Error", 5) == 0)
1810  {
1811  uves_msg_error("%s:%d: %s", file, line, msg);
1812  }
1813  else if (strncmp(msg, "Warning", 7) == 0)
1814  {
1815  uves_msg_warning("%s: %s", function, msg);
1816  }
1817  else
1818  {
1819  /* indented */
1820  uves_msg_low("%s: %s", function, msg);
1821  }
1822 
1823 // cleanup:
1824  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1825 }
1826 
1827 /*----------------------------------------------------------------------------*/
1855 /*----------------------------------------------------------------------------*/
1856 int flames_midas_scfinf(const char *name, int fno, int *ibuf)
1857 {
1858  FILE *file;
1859  uves_propertylist *header = NULL;
1860 
1861  uves_msg_debug("fno = %d", fno);
1862 
1863  if (name == NULL) return 1;
1864 
1865  /* Test for existence */
1866  file = fopen(name, "r");
1867  if (file == NULL)
1868  {
1869  uves_msg_debug("File %s could not be opened", name);
1870  return 1;
1871  }
1872  uves_msg_debug("File %s could be opened", name);
1873  fclose(file);
1874 
1875  if (fno == 3) {
1876  /* The FLAMES code needs only the information about the
1877  file type which is written to ibuf[0] */
1878  if (uves_get_nextensions(name) > 0) {
1879  ibuf[0] = F_TBL_TYPE;
1880  }
1881  else {
1882  ibuf[0] = F_IMA_TYPE;
1883  }
1884  }
1885  else if (fno == 4)
1886  {
1887  /* The FLAMES code needs only the data type
1888  which is written to ibuf[1] */
1889  int bitpix;
1890 
1891  check( header = uves_propertylist_load(name, 0),
1892  "Could not load %s primary header", name);
1893 
1894  check( bitpix = uves_pfits_get_bitpix(header),
1895  "Could not get BITPIX from %s", name);
1896 
1897  uves_msg_debug("BITPIX is %d", bitpix);
1898 
1899  switch (bitpix) {
1900  case 16: ibuf[1] = D_I2_FORMAT; break; /* 16 bit signed integer */
1901  case 32: ibuf[1] = D_I4_FORMAT; break; /* 32 bit signed integer */
1902  case -32: ibuf[1] = D_R4_FORMAT; break; /* 32 bit floating point */
1903  case -64: ibuf[1] = D_R8_FORMAT; break; /* 64 bit floating point */
1904  default:
1905  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1906  "Cannot convert BITPIX = %d to DATTYPE",
1907  bitpix);
1908  break;
1909  }
1910  }
1911  else if (fno == 99)
1912  {
1913  /* Just test for file existence */
1914  }
1915  else
1916  {
1917  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
1918  "fno = %d is not needed by FLAMES code", fno);
1919  }
1920 
1921  cleanup:
1922  uves_free_propertylist(&header);
1923  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1924 }
1925 
1926 /*----------------------------------------------------------------------------*/
1936 /*----------------------------------------------------------------------------*/
1937 int flames_midas_scfopn(const char *name, int dattype, int newopn, int filtype,
1938  int *imno)
1939 {
1940  uves_msg_debug("Trying to open %s", name);
1941 
1942  if (filtype == F_IMA_TYPE) {
1943 
1944  if (newopn == 0) {
1945 
1946  /* Find first open slot */
1947  int i;
1948  bool found = false;
1949  for (i = 0; !found && i < MAX_OPEN; i++)
1950  {
1951  if (!frame_is_open(i))
1952  {
1953  cpl_type type;
1954 
1955  found = true;
1956  *imno = i;
1957 
1958  type = flames_midas_image_dtype_to_cpltype(dattype);
1959 
1960  frame_new_image(*imno, name, NULL, false,
1961  NULL, type, dattype);
1962 
1963  uves_msg_debug("Opened image no. %d: %s as type %s",
1964  i, name,
1965  uves_tostring_cpl_type(type));
1966  }
1967  }
1968 
1969  assure( found, CPL_ERROR_UNSUPPORTED_MODE,
1970  "Cannot open more than %d image files",
1971  MAX_OPEN);
1972  }
1973  else
1974  {
1975 
1976  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
1977  }
1978  }
1979  else
1980  {
1981  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
1982  }
1983 
1984  cleanup:
1985  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
1986 }
1987 
1988 /*----------------------------------------------------------------------------*/
2002 /*----------------------------------------------------------------------------*/
2003 int flames_midas_scfcre(const char *name, int dattype, int iomode, int filtype,
2004  int size, int *imno)
2005 {
2006  if (filtype == F_IMA_TYPE)
2007  {
2008  if (iomode == F_O_MODE) /* output: create empty header */
2009  {
2010 
2011  /* Find first open slot */
2012  int i;
2013  bool found = false;
2014  cpl_type type;
2015 
2016  for (i = 0; !found && i < MAX_OPEN; i++)
2017  {
2018 
2019  if (!frame_is_open(i))
2020  {
2021  found = true;
2022  *imno = i;
2023 
2024  uves_msg_debug("Opened image no. %d: %s",
2025  i, name);
2026  }
2027  }
2028 
2029  assure( found, CPL_ERROR_UNSUPPORTED_MODE,
2030  "Cannot open more than %d image files",
2031  MAX_OPEN);
2032 
2033  type = flames_midas_image_dtype_to_cpltype(dattype);
2034 
2035  /* Create Nx1 image, set proper size later */
2036  frame_new_image(*imno, name, uves_propertylist_new(), true,
2037  cpl_image_new(size, 1, type), type, dattype);
2038 
2039  }
2040 
2041  else
2042  {
2043  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
2044  }
2045  }
2046  else
2047  {
2048  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
2049  }
2050 
2051 
2052  passure( invariant(*imno), " ");
2053 
2054  cleanup:
2055  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2056 }
2057 
2058 /*----------------------------------------------------------------------------*/
2064 /*----------------------------------------------------------------------------*/
2065 static int
2067 {
2068  cpl_property **cards = NULL;
2069  fitsfile *fptr = NULL;
2070  int fio_status = 0;
2071 
2072  passure( invariant(id), " ");
2073  if (!frame_is_open(id)) {
2074 
2075 
2076  uves_msg_warning("%s number %d is not open, cannot close",
2077  frames[id].is_image ? "Image" : "Table",
2078  id);
2079 
2080  }
2081  else {
2082  if (frames[id].need_to_save) {
2083  char type;
2084  int bytelem;
2085  int naxis;
2086 
2087  uves_msg_debug("Saving frame %s to disk", frames[id].filename);
2088 
2089  check( load_frame(id),
2090  "Could not load frame %s", frames[id].filename);
2091 
2092  check( load_frame_header(id),
2093  "Could not load %s header", frames[id].filename);
2094 
2095  check( cards = get_descr_info(id, "NPIX",
2096  &type, &naxis, &bytelem),
2097  "Could not get info on descriptor NPIX");
2098 
2099  check( convert_to_history(&frames[id].header),
2100  "Could not convert header");
2101 
2102  /* Note header is free'd below, so changing it is ok */
2103  if (frames[id].is_image)
2104  {
2105 
2106 
2107  bool save_as_bitpix16 =
2108  (frames[id].data.image.dtype == D_I1_FORMAT ||
2109  frames[id].data.image.dtype == D_I2_FORMAT);
2110  /* Save D_I1_FORMAT / D_I2_FORMAT (masks) as 16 bit unsigned,
2111  otherwise 32 bit signed */
2112 
2113  bool save_as_1d = (naxis == 1);
2114  /* Don't save 2d images as 1d, we will loose START/STEP descriptors */
2115 
2116  assure( naxis == 1 || naxis == 2 || naxis == 3 || naxis == 4,
2117  CPL_ERROR_UNSUPPORTED_MODE,
2118  "Cannot save image with NAXIS = %d", naxis);
2119 
2120  uves_msg_debug("Saving %dd image", naxis);
2121 
2122  check( uves_save_image(frames[id].data.image.image,
2123  frames[id].filename,
2124  frames[id].header,
2125  save_as_bitpix16,
2126  save_as_1d),
2127  "Error saving image %s", frames[id].filename);
2128 
2129  if (naxis == 2 || naxis == 3 || naxis == 4) {
2130  int NAXIS[4];
2131  int unit, null;
2132  int actvals;
2133  char dummy[100]; /* More than length of FITS key record */
2134  char err_message[81]; /* long enough according to CFITSIO doc. */
2135  int current_naxis; /* As written by the previous uves_save_image()
2136  call */
2137 
2138  assure( 0 == flames_midas_scdrdi(id, "NPIX",
2139  1, naxis,
2140  &actvals, NAXIS,
2141  &unit, &null),
2142  CPL_ERROR_ILLEGAL_INPUT,
2143  "Failed to read NPIX");
2144 
2145  assure( actvals == naxis, CPL_ERROR_ILLEGAL_INPUT,
2146  "naxis = %d but actvals = %d", naxis, actvals);
2147 
2148  /* CPL and QFITS cannot change a FITS header without
2149  load/saving the data buffer
2150  so use CFITSIO for this basic task */
2151 
2152  fits_open_file(&fptr, frames[id].filename, READWRITE, &fio_status);
2153 
2154  assure( fio_status == 0, CPL_ERROR_ILLEGAL_OUTPUT,
2155  "Failed to open file %s", frames[id].filename);
2156 
2157  /* Move to beginning of header, then to location of NAXIS (which should already exist) */
2158  fits_read_record(fptr, 0, dummy, &fio_status);
2159  /* fits_read_card(fptr, (char*)"NAXIS", dummy, &fio_status); */
2160  fits_read_key(fptr, TINT, (char*)"NAXIS", &current_naxis, NULL, &fio_status);
2161 
2162  fits_update_key(fptr, TINT, (char*)"NAXIS", &naxis, (char*)"Empty unit", &fio_status);
2163  fits_update_key(fptr, TINT, (char*)"NAXIS1", &NAXIS[0], (char*)"Empty unit", &fio_status);
2164 
2165  if (current_naxis < 2) {
2166  fits_insert_card(fptr, (char*)"NAXIS2", &fio_status);
2167  }
2168  fits_update_key(fptr, TINT, (char*)"NAXIS2", &NAXIS[1], (char*)"Empty unit", &fio_status);
2169 
2170  if (naxis >= 3) {
2171  fits_insert_card(fptr, (char*)"NAXIS3", &fio_status);
2172  fits_update_key(fptr, TINT, (char*)"NAXIS3", &NAXIS[2], (char*)"Empty unit", &fio_status);
2173  }
2174 
2175  if (naxis >= 4) {
2176  fits_insert_card(fptr, (char*)"NAXIS4", &fio_status);
2177  fits_update_key(fptr, TINT, (char*)"NAXIS4", &NAXIS[3], (char*)"Empty unit", &fio_status);
2178  }
2179 
2180  fits_close_file(fptr, &fio_status);
2181 
2182  if (fio_status != 0) fits_read_errmsg(err_message);
2183  assure( fio_status == 0, CPL_ERROR_ILLEGAL_OUTPUT,
2184  "Error '%s' code %d while updating %s FITS header",
2185  err_message, fio_status, frames[id].filename);
2186  }
2187 
2188  }
2189  else
2190  {
2191  cpl_table_set_size(frames[id].data.table.table,
2192  frames[id].data.table.maxrow);
2193 
2194  check( uves_table_save(frames[id].data.table.table,
2195  frames[id].header, /* Primary header */
2196  NULL, /* Ext. header */
2197  frames[id].filename,
2198  CPL_IO_DEFAULT),
2199  "Error saving table %s", frames[id].filename);
2200  }
2201 
2202  frames[id].need_to_save = false;
2203 
2204  }
2205  else
2206  {
2207  uves_msg_debug("Closing %s %s (don't save to disk)",
2208  frames[id].is_image ? "image" : "table",
2209  frames[id].filename);
2210  }
2211 
2212  frame_free(id);
2213 
2214  }
2215 
2216  passure( !frame_is_open(id), " ");
2217  passure( invariant(id), " ");
2218 
2219  cleanup:
2220  cpl_free(cards); cards = NULL;
2221  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2222 }
2223 
2224 /*----------------------------------------------------------------------------*/
2231 /*----------------------------------------------------------------------------*/
2232 int flames_midas_scfclo(int imno)
2233 {
2234  return frame_close(imno);
2235 }
2236 
2237 /*----------------------------------------------------------------------------*/
2249 /*----------------------------------------------------------------------------*/
2250 int flames_midas_scfget(int imno, int felem, int size, int *actsize, char *bufadr)
2251 {
2252  //cpl_type type;
2253 
2254  passure( invariant(imno), " ");
2255 
2256  assure( frame_is_open(imno) && frames[imno].is_image, CPL_ERROR_ILLEGAL_INPUT,
2257  "Image no. %d is not open", imno);
2258 
2259  check( load_frame(imno),
2260  "Could not load image %s", frames[imno].filename);
2261 
2262  assure( (felem-1) + size <=
2263  cpl_image_get_size_x(frames[imno].data.image.image)*
2264  cpl_image_get_size_y(frames[imno].data.image.image),
2265  CPL_ERROR_ACCESS_OUT_OF_RANGE,
2266  "Cannot read %d bytes of CPL image of size %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " position %d",
2267  size,
2268  cpl_image_get_size_x(frames[imno].data.image.image),
2269  cpl_image_get_size_y(frames[imno].data.image.image),
2270  felem-1);
2271 
2272  switch(frames[imno].data.image.type) {
2273  case CPL_TYPE_INT:
2274  {
2275  int *buffer;
2276  int i;
2277  buffer = cpl_image_get_data_int(frames[imno].data.image.image);
2278  buffer += (felem-1);
2279 
2280  switch(frames[imno].data.image.dtype) {
2281  case D_I1_FORMAT:
2282  for (i = 0; i < size; i++)
2283  {
2284  ((char *)bufadr)[i] = buffer[i];
2285  }
2286  break;
2287  case D_I2_FORMAT:
2288  case D_I4_FORMAT:
2289  for (i = 0; i < size; i++)
2290  {
2291  ((int32_t *)bufadr)[i] = buffer[i];
2292  }
2293  break;
2294  default:
2295  assure_nomsg( false, CPL_ERROR_UNSUPPORTED_MODE );
2296  break;
2297  }
2298  *actsize = size;
2299  }
2300  break;
2301  case CPL_TYPE_FLOAT:
2302  {
2303  float *buffer;
2304  int i;
2305  buffer = cpl_image_get_data_float(frames[imno].data.image.image);
2306  buffer += (felem-1);
2307 
2308  for (i = 0; i < size; i++)
2309  {
2310  ((float *)bufadr)[i] = buffer[i];
2311  }
2312  *actsize = size;
2313  }
2314  break;
2315  default:
2316  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Type is %s",
2317  uves_tostring_cpl_type(frames[imno].data.image.type));
2318  break;
2319  }
2320 
2321  passure( invariant(imno), " ");
2322 
2323  cleanup:
2324  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2325 }
2326 
2327 
2328 /*----------------------------------------------------------------------------*/
2338 /*----------------------------------------------------------------------------*/
2339 int flames_midas_scfput(int imno, int felem, int size, const char *bufadr)
2340 {
2341  int i;
2342 
2343  passure( invariant(imno), " ");
2344 
2345  assure( frame_is_open(imno) && frames[imno].is_image, CPL_ERROR_ILLEGAL_INPUT,
2346  "Image no. %d is not open", imno);
2347 
2348  /* Load image if necessary, then overwrite part, or all of data buffer */
2349  check( load_frame(imno),
2350  "Could not load image %s", frames[imno].filename);
2351 
2352  assure( (felem-1) + size <=
2353  cpl_image_get_size_x(frames[imno].data.image.image)*
2354  cpl_image_get_size_y(frames[imno].data.image.image),
2355  CPL_ERROR_ACCESS_OUT_OF_RANGE,
2356  "Cannot write %d pixels to CPL image of size %" CPL_SIZE_FORMAT "x%" CPL_SIZE_FORMAT " position %d",
2357  size,
2358  cpl_image_get_size_x(frames[imno].data.image.image),
2359  cpl_image_get_size_y(frames[imno].data.image.image),
2360  felem-1);
2361 
2362  uves_msg_debug("Writing %d pixels to image %s",
2363  size, frames[imno].filename);
2364 
2365  switch(frames[imno].data.image.type) {
2366  case CPL_TYPE_INT:
2367  {
2368  int *buffer;
2369  buffer = cpl_image_get_data_int(frames[imno].data.image.image);
2370  buffer += (felem-1);
2371 
2372  switch(frames[imno].data.image.dtype) {
2373  case D_I1_FORMAT:
2374  for (i = 0; i < size; i++)
2375  {
2376  buffer[i] = ((char *)bufadr)[i];
2377  }
2378  break;
2379  case D_I2_FORMAT:
2380  case D_I4_FORMAT:
2381  for (i = 0; i < size; i++)
2382  {
2383  buffer[i] = ((int *)bufadr)[i];
2384  }
2385  break;
2386  default:
2387  assure_nomsg( false, CPL_ERROR_UNSUPPORTED_MODE );
2388  break;
2389  }
2390  }
2391  break;
2392  case CPL_TYPE_FLOAT:
2393  {
2394  float *buffer;
2395  buffer = cpl_image_get_data_float(frames[imno].data.image.image);
2396  buffer += (felem-1);
2397 
2398  for (i = 0; i < size; i++)
2399  {
2400  buffer[i] = ((float *)bufadr)[i];
2401  }
2402  }
2403  break;
2404  case CPL_TYPE_DOUBLE:
2405  {
2406  double *buffer;
2407  buffer = cpl_image_get_data_double(frames[imno].data.image.image);
2408  buffer += (felem-1);
2409 
2410  for (i = 0; i < size; i++)
2411  {
2412  buffer[i] = ((double *)bufadr)[i];
2413  }
2414  }
2415  break;
2416  default:
2417  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Type is %s",
2418  uves_tostring_cpl_type(frames[imno].data.image.type));
2419  break;
2420  }
2421 
2422  frames[imno].need_to_save = true; /* Memory buffer has changed */
2423 
2424  passure( invariant(imno), " ");
2425 
2426  cleanup:
2427  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2428 }
2429 
2430 /*----------------------------------------------------------------------------*/
2444 /*----------------------------------------------------------------------------*/
2445 int flames_midas_scdfnd(int id, const char *descr,
2446  char *type, int *noelem, int *bytelem)
2447 {
2448  cpl_property **cards = NULL;
2449 
2450  passure( invariant(id), " ");
2451  assure_nomsg( descr != NULL, CPL_ERROR_NULL_INPUT );
2452 
2453  if (strcmp(descr, "LHCUTS") == 0)
2454  {
2455  int datamin_noelem, datamax_noelem;
2456  char datamin_type, datamax_type;
2457 
2458  *noelem = 2; /* LHCUTS1 and LHCUTS2 always exist */
2459  *type ='R';
2460 
2461  flames_midas_scdfnd(id, "DATAMIN", &datamin_type, &datamin_noelem, bytelem);
2462  flames_midas_scdfnd(id, "DATAMAX", &datamax_type, &datamax_noelem, bytelem);
2463 
2464  assure( datamin_noelem <= 1, CPL_ERROR_ILLEGAL_INPUT,
2465  "Multiple (%d) DATAMIN keywords found", datamin_noelem);
2466 
2467  assure( datamax_noelem <= 1, CPL_ERROR_ILLEGAL_INPUT,
2468  "Multiple (%d) DATAMIN keywords found", datamax_noelem);
2469 
2470  if (datamin_noelem > 0)
2471  {
2472  *noelem = 3;
2473  assure( datamin_type == 'D', CPL_ERROR_TYPE_MISMATCH,
2474  "DATAMIN has type %c, %c expected", datamin_type, 'D');
2475 
2476  if (datamax_noelem > 0)
2477  {
2478  *noelem = 4;
2479  assure( datamax_type == 'D', CPL_ERROR_TYPE_MISMATCH,
2480  "DATAMAX has type %c, %c expected", datamax_type, 'D');
2481  }
2482  }
2483 
2484  }
2485  else
2486  {
2487  check( cards = get_descr_info(id, descr,
2488  type, noelem, bytelem),
2489  "Could not get info on descriptor %s", descr);
2490 
2491  if (cards == NULL)
2492  {
2493  *type = ' ';
2494  uves_msg_debug("Descriptor %s not found",descr);
2495  }
2496  else
2497  {
2498  uves_msg_debug("Found descriptor %s, type = %c, length = %d",
2499  descr, *type, *noelem);
2500  }
2501  }
2502 
2503  passure( invariant(id), " ");
2504 
2505  cleanup:
2506  cpl_free(cards); cards = NULL;
2507 
2508  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2509 }
2510 
2511 
2512 
2513 /*----------------------------------------------------------------------------*/
2527 /*----------------------------------------------------------------------------*/
2528 int flames_midas_scdprs(int id, const char *descr,
2529  char *type, int *noelem, int *bytelem)
2530 {
2531  cpl_property **cards = NULL;
2532 
2533  passure( invariant(id), " ");
2534  assure_nomsg( descr != NULL, CPL_ERROR_NULL_INPUT );
2535 
2536  if (strcmp(descr, "LHCUTS") == 0)
2537  {
2538  int datamin_noelem, datamax_noelem;
2539  char datamin_type, datamax_type;
2540 
2541  *noelem = 2; /* LHCUTS1 and LHCUTS2 always exist */
2542  *type ='R';
2543 
2544  flames_midas_scdfnd(id, "DATAMIN", &datamin_type, &datamin_noelem, bytelem);
2545  flames_midas_scdfnd(id, "DATAMAX", &datamax_type, &datamax_noelem, bytelem);
2546 
2547  assure( datamin_noelem <= 1, CPL_ERROR_ILLEGAL_INPUT,
2548  "Multiple (%d) DATAMIN keywords found", datamin_noelem);
2549 
2550  assure( datamax_noelem <= 1, CPL_ERROR_ILLEGAL_INPUT,
2551  "Multiple (%d) DATAMIN keywords found", datamax_noelem);
2552 
2553  if (datamin_noelem > 0)
2554  {
2555  *noelem = 3;
2556  assure( datamin_type == 'D', CPL_ERROR_TYPE_MISMATCH,
2557  "DATAMIN has type %c, %c expected", datamin_type, 'D');
2558 
2559  if (datamax_noelem > 0)
2560  {
2561  *noelem = 4;
2562  assure( datamax_type == 'D', CPL_ERROR_TYPE_MISMATCH,
2563  "DATAMAX has type %c, %c expected", datamax_type, 'D');
2564  }
2565  }
2566 
2567  }
2568  else
2569  {
2570  check( cards = get_descr_info(id, descr,
2571  type, noelem, bytelem),
2572  "Could not get info on descriptor %s", descr);
2573 
2574  if (cards == NULL)
2575  {
2576  *type = ' ';
2577  uves_msg_debug("Descriptor %s not found",descr);
2578  cpl_free(cards); cards = NULL;
2579  return 1;
2580  }
2581  else
2582  {
2583  uves_msg_debug("Found descriptor %s, type = %c, length = %d",
2584  descr, *type, *noelem);
2585  }
2586  }
2587 
2588  passure( invariant(id), " ");
2589 
2590  cleanup:
2591  cpl_free(cards); cards = NULL;
2592 
2593  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2594 }
2595 
2596 /*----------------------------------------------------------------------------*/
2611 /*----------------------------------------------------------------------------*/
2612 static int
2613 scdrd(char expected_type, int id, const char *descr,
2614  int felem, int maxvals,
2615  int *actvals, void *values,
2616  int *unit, int *null)
2617 {
2618  char type;
2619  int length;
2620  int bytelem;
2621  cpl_property **cards = NULL;
2622  int i;
2623  if (unit) {} //to remove compilation warning: this is not used
2624  if (null) {} //to remove compilation warning: this is not used
2625 
2626  passure( invariant(id), " ");
2627 
2628  check( cards = get_descr_info(id, descr, &type,
2629  &length, &bytelem),
2630  "Could not get info on descriptor %s", descr);
2631 
2632  assure( cards != NULL, CPL_ERROR_DATA_NOT_FOUND,
2633  "Descriptor %s not found in file %s", descr, frames[id].filename);
2634 
2635  /* Allow conversion R -> D */
2636  assure( (expected_type == 'D' && type == 'R')
2637  ||
2638  type == expected_type, CPL_ERROR_TYPE_MISMATCH,
2639  "Descriptor %s has type %c, %c expected",
2640  descr, type, expected_type);
2641 
2642  passure( type != 'C' || felem == 1, "'%c' %d", type, felem);
2643 
2644  *actvals = 0;
2645  //uves_msg_warning("length=%d",length);
2646  for (i = felem-1; i < length; i++)
2647  {
2648  if (*actvals < maxvals)
2649  {
2650  uves_msg_debug("Getting %d of %d (max %d) values of descriptor %s",
2651  *actvals + 1, length - (felem-1), maxvals, descr);
2652 
2653  switch(type) {
2654  case 'I':
2655  ((int *)values)[i-(felem-1)] = cpl_property_get_int(cards[i]);
2656  uves_msg_debug("Value = %d", ((int *)values)[i-(felem-1)]);
2657  break;
2658  case 'D':
2659  ((double *)values)[i-(felem-1)] = cpl_property_get_double(cards[i]);
2660  uves_msg_debug("Value = %g", ((double *)values)[i-(felem-1)]);
2661  break;
2662  case 'R':
2663  switch(expected_type) {
2664  case 'R':
2665  ((float *)values)[i-(felem-1)] = cpl_property_get_float(cards[i]);
2666  uves_msg_debug("Value = %g", ((float *)values)[i-(felem-1)]);
2667  break;
2668  case 'D':
2669  ((double *)values)[i-(felem-1)] = cpl_property_get_float(cards[i]);
2670  uves_msg_debug("Value = %g", ((double *)values)[i-(felem-1)]);
2671  break;
2672  default:
2673  passure( false, " ");
2674  break;
2675  }
2676  break;
2677  case 'C':
2678  ((char *)values)[i-(felem-1)] = cpl_property_get_string(cards[0])[i];
2679  uves_msg_debug("Value = %c", ((char *)values)[i-(felem-1)]);
2680  break;
2681  default:
2682  assure( false, CPL_ERROR_INVALID_TYPE, "Type is %c", type);
2683  break;
2684  }
2685  *actvals += 1;
2686  }
2687  }
2688 
2689  if (type == 'C' && *actvals < maxvals)
2690  {
2691  /* length is the string length,
2692  terminate with 0
2693  This character does not count in actvals
2694  but is include in maxvals
2695  */
2696  ((char *)values)[length-(felem-1)] = '\0';
2697  }
2698 
2699  /* unit, null not implemented by MIDAS */
2700 
2701  passure( invariant(id), " ");
2702 
2703  cleanup:
2704  cpl_free(cards); cards = NULL;
2705 
2706  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2707 }
2708 /*----------------------------------------------------------------------------*/
2715 /*----------------------------------------------------------------------------*/
2716 int flames_midas_scdrdi(int id, const char *descr,
2717  int felem, int maxvals,
2718  int *actvals, int *values,
2719  int *unit, int *null)
2720 {
2721  char *char_values = NULL;
2722 
2723 #if 0
2724  if (strcmp(descr, "MAXFIBRES") == 0)
2725  {
2726  char_values = cpl_malloc(maxvals + 1);
2727  assure_mem( char_values );
2728  char_values[0] = '\0';
2729 
2730  assure( felem == 1, CPL_ERROR_UNSUPPORTED_MODE,
2731  "first element no. (%d) is not 1", felem);
2732 
2733  check( scdrd('C', imno, descr, felem, maxvals, actvals, char_values, unit, null),
2734  "Reading %s as string failed", descr);
2735 
2736  assure( strlen(char_values) == 1, CPL_ERROR_ILLEGAL_INPUT,
2737  "MAXFIBRES value (%s) has length different from 1",
2738  char_values);
2739 
2740  /* We have a string of length 1, convert to integer */
2741  errno = 0;
2742  values[0] = atoi(char_values);
2743  assure( errno == 0, CPL_ERROR_ILLEGAL_OUTPUT,
2744  "Conversion of %s to integer failed", char_values);
2745 
2746  cpl_msg_debug("Got value %s (%d)", char_values, values[0]);
2747  }
2748  else
2749 #endif
2750  {
2751  /* Ok to return here, nothing alloc'ed */
2752  return scdrd('I', id, descr, felem, maxvals, actvals, values, unit, null);
2753  }
2754 
2755 /* cleanup: */
2756  uves_free_string(&char_values);
2757  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
2758 }
2759 
2760 /*----------------------------------------------------------------------------*/
2766 /*----------------------------------------------------------------------------*/
2767 int flames_midas_scdrdd(int id, const char *descr,
2768  int felem, int maxvals,
2769  int *actvals, double *values,
2770  int *unit, int *null)
2771 {
2772  return scdrd('D', id, descr, felem, maxvals, actvals, values, unit, null);
2773 }
2774 
2775 /*----------------------------------------------------------------------------*/
2781 /*----------------------------------------------------------------------------*/
2782 int flames_midas_scdrdr(int id, const char *descr,
2783  int felem, int maxvals,
2784  int *actvals, float *values,
2785  int *unit, int *null)
2786 {
2787  if (strcmp("LHCUTS", descr) == 0 && felem < 3)
2788  {
2789  int i;
2790  bool success = true;
2791 
2792  for (i = felem; i < felem+maxvals; i++)
2793  {
2794  double val;
2795  if (1 <= i && i <= 2)
2796  {
2797  uves_msg_debug("Do not read LHCUTS%d", i);
2798  }
2799  else if (i == 3)
2800  {
2801  success = success &&
2802  (flames_midas_scdrdd(id, "DATAMIN", i, 1,
2803  actvals,
2804  &val,
2805  unit, null)) == 0;
2806 
2807  values[i-felem] = (float) val;
2808  }
2809  else if (i == 4)
2810  {
2811  success = success &&
2812  (flames_midas_scdrdd(id, "DATAMAX", i, 1,
2813  actvals,
2814  &val,
2815  unit, null)) == 0;
2816  values[i-felem] = (float) val;
2817  }
2818  else
2819  {
2820  success = false;
2821  }
2822  }
2823  return success ? 0 : 1;
2824  }
2825  else
2826  {
2827  return scdrd('R', id, descr, felem, maxvals, actvals, values, unit, null);
2828  }
2829 }
2830 
2831 /*----------------------------------------------------------------------------*/
2841 /*----------------------------------------------------------------------------*/
2842 int flames_midas_scdrdc(int id, const char *descr,
2843  int noelem,
2844  int felem, int maxvals,
2845  int *actvals, char *values,
2846  int *unit, int *null)
2847 {
2848  int returnvalue = 1;
2849 
2850  assure( noelem == sizeof(char), CPL_ERROR_UNSUPPORTED_MODE, "Implement me" );
2851  assure( felem == 1, CPL_ERROR_UNSUPPORTED_MODE, "Implement me" );
2852 
2853  returnvalue = scdrd('C', id, descr, felem, maxvals, actvals, values, unit, null);
2854 
2855  cleanup:
2856  return returnvalue;
2857 }
2858 
2859 
2860 
2861 /*----------------------------------------------------------------------------*/
2879 /*----------------------------------------------------------------------------*/
2880 static int
2881 scdwr(char type_to_write, int id, const char *descr, const void *values,
2882  int felem, int nval, const int *unit)
2883 {
2884  char type = '-';
2885  int length, bytelem, i;
2886  cpl_property **cards = NULL;
2887  cpl_property **cards_extra = NULL;
2888 
2889 
2890  passure( invariant(id), " ");
2891 
2892  assure( frame_is_open(id), CPL_ERROR_ILLEGAL_INPUT,
2893  "Frame no. %d is not open", id);
2894 
2895  check( cards = get_descr_info(id, descr,
2896  &type, &length, &bytelem),
2897  "Could not get info on descriptor %s", descr);
2898 
2899  if (cards == NULL) {
2900  int number_of_cards = (type_to_write == 'C') ? 1 : (felem-1)+nval;
2901  int nexisting = 0;
2902 
2903  type = type_to_write;
2904  check( cards = create_descr(frames[id].header, descr, type,
2905  number_of_cards, nexisting),
2906  "Could not create %d %s descriptors",
2907  number_of_cards, descr);
2908  }
2909  else {
2910  assure( type == type_to_write ||
2911  (type == 'D' && type_to_write == 'R'),
2912  CPL_ERROR_TYPE_MISMATCH,
2913  "Cannot write type %c data to type %c descriptor %s",
2914  type_to_write, type, descr);
2915 
2916  if (type_to_write != 'C' &&
2917  (felem-1) + nval > length)
2918  /* Create additional descriptors */
2919  {
2920  int number_of_extra = (felem-1) + nval - length;
2921  int ncards;
2922 
2923  /* Count existing descriptors */
2924  ncards = 0;
2925  while(cards[ncards] != NULL) ncards++;
2926 
2927  uves_msg_debug("Only %d existing %s descriptor(s), add another %d",
2928  ncards, descr, number_of_extra);
2929 
2930  check( cards_extra
2931  = create_descr(frames[id].header, descr, type,
2932  number_of_extra, ncards),
2933  "Could not create %d %s descriptors",
2934  number_of_extra, descr);
2935 
2936  /* Append to existing */
2937  cards = cpl_realloc(cards, (ncards + number_of_extra + 1)*sizeof(cpl_property *));
2938 
2939  for (i = ncards; i < ncards + number_of_extra; i++)
2940  {
2941  cards[i] = cards_extra[i-ncards];
2942  }
2943 
2944  cards[ncards+number_of_extra] = NULL;
2945  }
2946  else {
2947  uves_msg_debug("Do not add new cards for descriptor %s", descr);
2948  }
2949  }
2950 
2951  /* Properties now exist in correct number, with correct type */
2952  for (i = 0; i < ((type_to_write == 'C') ? 1 : nval); i++) {
2953  if (type_to_write == 'I') {
2954  uves_msg_debug("Writing %d. of %d values (%d) to cards[%d]",
2955  i+1,
2956  ((type_to_write == 'C') ? 1 : nval),
2957  ((const int *)values)[i],
2958  (felem-1) + i);
2959  }
2960  else {
2961  uves_msg_debug("Writing %d. of %d values to cards[%d]",
2962  i+1,
2963  ((type_to_write == 'C') ? 1 : nval),
2964  (felem-1) + i);
2965  }
2966 
2967  /* Allow conversion float -> double */
2968  switch(type_to_write) {
2969  case 'I': cpl_property_set_int (cards[(felem-1) + i], ((const int *)values)[i]); break;
2970  case 'R':
2971  switch(type) {
2972  case 'R':
2973  cpl_property_set_float (cards[(felem-1) + i], ((const float *)values)[i]); break;
2974  case 'D':
2975  cpl_property_set_double(cards[(felem-1) + i], ((const float *)values)[i]); break;
2976  default:
2977  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
2978  "Cannot write type '%c' values to type '%c' descriptor",
2979  type_to_write, type);
2980  break;
2981  }
2982  break;
2983  case 'C': cpl_property_set_string(cards[(felem-1) + i], (const char *)values); break;
2984  case 'D': cpl_property_set_double(cards[(felem-1) + i], ((const double *)values)[i]); break;
2985  default:
2986  assure( false,CPL_ERROR_UNSUPPORTED_MODE, "Implement me"); break;
2987  }
2988 
2989  }
2990 
2991  /* unit not implemented by MIDAS */
2992 
2993  frames[id].need_to_save = true;
2994  /* and in order to be able to save the header with CPL,
2995  we need to also have the image in memory (if not already) */
2996  check( load_frame(id),
2997  "Could not load frame %s", frames[id].filename );
2998 
2999  passure( invariant(id), " ");
3000 
3001  cleanup:
3002  cpl_free(cards); cards = NULL;
3003  cpl_free(cards_extra); cards_extra = NULL;
3004 
3005  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3006 }
3007 
3008 /*----------------------------------------------------------------------------*/
3014 /*----------------------------------------------------------------------------*/
3015 int flames_midas_scdwri(int id, const char *descr, const int *values,
3016  int felem, int nval, const int *unit)
3017 {
3018  if (strcmp(descr, "NPIX") == 0)
3019  /* MIDAS NPIXi maps to FITS NAXISi */
3020  {
3021  cpl_type type;
3022  int *buffer_int=NULL;
3023  float *buffer_float=NULL;
3024  double *buffer_double=NULL;
3025  int size=0;
3026 
3027  assure( nval == 1 || nval == 2 || nval == 3 || nval == 4,
3028  CPL_ERROR_UNSUPPORTED_MODE,
3029  "Only 2d, 3d and 4d (not %dd) images supported",
3030  nval);
3031 
3032  assure( frames[id].is_image, CPL_ERROR_ILLEGAL_INPUT,
3033  "Cannot write NPIX to table %s", frames[id].filename);
3034 
3035  switch(nval) {
3036  case 1: size = values[0]; break;
3037  case 2: size = values[0] * values[1]; break;
3038  case 3: size = values[0] * values[1] * values[2]; break;
3039  case 4: size = values[0] * values[1] * values[2] * values[3]; break;
3040  default:
3041  passure( false, "Impossible");
3042  break;
3043  }
3044 
3045  if (frames[id].data.image.image == NULL) {
3046  frames[id].data.image.image =
3047  cpl_image_new(size, 1,
3048  frames[id].data.image.type);
3049  }
3050 
3051  assure( size ==
3052  cpl_image_get_size_x(frames[id].data.image.image) *
3053  cpl_image_get_size_y(frames[id].data.image.image),
3054  CPL_ERROR_INCOMPATIBLE_INPUT,
3055  "Cannot set image %s NAXIS to %d because the "
3056  "image memory buffer size is %" CPL_SIZE_FORMAT "",
3057  frames[id].filename,
3058  size,
3059  cpl_image_get_size_x(frames[id].data.image.image) *
3060  cpl_image_get_size_y(frames[id].data.image.image));
3061 
3062  /* Now unwrap + wrap the image structure, but keep
3063  the buffer unchanged */
3064  type = cpl_image_get_type(frames[id].data.image.image);
3065  if (nval == 2) {
3066  /* This is redundant now that NAXIS is overwritten when closing */
3067  uves_msg_debug("Setting image %s (type %s) size to %dx%d",
3068  frames[id].filename,
3069  uves_tostring_cpl_type(type),
3070  values[0], values[1]);
3071  switch(type) {
3072  case CPL_TYPE_INT : buffer_int = cpl_image_get_data_int(frames[id].data.image.image); break;
3073  case CPL_TYPE_FLOAT : buffer_float = cpl_image_get_data_float(frames[id].data.image.image); break;
3074  case CPL_TYPE_DOUBLE: buffer_double = cpl_image_get_data_double(frames[id].data.image.image); break;
3075  default:
3076  assure( false, CPL_ERROR_INVALID_TYPE, "Type is %s",
3077  uves_tostring_cpl_type(type));
3078  break;
3079  }
3080 
3081 
3082  /* Deallocate, except buffer */
3083  cpl_image_unwrap(frames[id].data.image.image);
3084 
3085  switch(type) {
3086  case CPL_TYPE_INT : frames[id].data.image.image = cpl_image_wrap_int (values[0], values[1], buffer_int); break;
3087  case CPL_TYPE_FLOAT : frames[id].data.image.image = cpl_image_wrap_float (values[0], values[1], buffer_float); break;
3088  case CPL_TYPE_DOUBLE: frames[id].data.image.image = cpl_image_wrap_double(values[0], values[1], buffer_double); break;
3089  default:
3090  assure( false, CPL_ERROR_INVALID_TYPE, "Type is %s",
3091  uves_tostring_cpl_type(type));
3092  break;
3093  }
3094 
3095  }
3096  else {
3097  /* for 3d, 4d images don't change the CPL
3098  image axes. NAXISi will be overwritten when saving */
3099  }
3100  }
3101 
3102  scdwr('I', id, descr, values, felem, nval, unit);
3103 
3104  cleanup:
3105  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3106 }
3107 
3108 /*----------------------------------------------------------------------------*/
3114 /*----------------------------------------------------------------------------*/
3115 int flames_midas_scdwrd(int id, const char *descr, const double *values,
3116  int felem, int nval, const int *unit)
3117 {
3118  if (strcmp("CRPIX", descr) == 0 ||
3119  strcmp("CRVAL", descr) == 0 ||
3120  strcmp("CDELT", descr) == 0) {
3121  int i;
3122  bool success = true;
3123 
3124  for (i = felem; i < felem+nval; i++) {
3125  char descr_i[10];
3126 
3127  sprintf(descr_i, "%s%i", descr, i);
3128  success = success &&
3129  (flames_midas_scdwrd(id, descr_i, &values[i-felem],
3130  felem, 1, unit) == 0);
3131  }
3132 
3133  return success ? 0 : 1;
3134  }
3135 
3136  return scdwr('D', id, descr, values, felem, nval, unit);
3137 }
3138 
3139 /*----------------------------------------------------------------------------*/
3145 /*----------------------------------------------------------------------------*/
3146 int flames_midas_scdwrr(int id, const char *descr, const float *values,
3147  int felem, int nval, const int *unit)
3148 {
3149  if (strcmp("LHCUTS", descr) == 0 && felem < 3) {
3150  int i;
3151  bool success = true;
3152 
3153  for (i = felem; i < felem+nval; i++)
3154  {
3155  if (1 <= i && i <= 2)
3156  {
3157  uves_msg_debug("Do not write LHCUTS%d", i);
3158  }
3159  else if (i == 3)
3160  {
3161  double val = (double) values[i-felem-1];
3162  success = success &&
3163  (flames_midas_scdwrd(id, "DATAMIN", &val,
3164  1, 1, unit) == 0);
3165  }
3166  else if (i == 4)
3167  {
3168  double val = (double) values[i-felem-1];
3169  success = success &&
3170  (flames_midas_scdwrd(id, "DATAMAX", &val,
3171  1, 1, unit) == 0);
3172  }
3173  else
3174  {
3175  success = false;
3176  }
3177  }
3178  return success ? 0 : 1;
3179  }
3180  else
3181  {
3182  return scdwr('R', id, descr, values, felem, nval, unit);
3183  }
3184 }
3185 
3186 /*----------------------------------------------------------------------------*/
3196 /*----------------------------------------------------------------------------*/
3197 int flames_midas_scdwrc(int id, const char *descr, int noelm, const char *values,
3198  int felem, int nval, const int *unit)
3199 {
3200  int returnvalue = 1;
3201  char* tmp_string=NULL;
3202 
3203  if (strcmp(descr, "CUNIT") == 0) {
3204  if (noelm == 1) {
3205  char val[17];
3206  int i;
3207 
3208  assure( nval % 16 == 0, CPL_ERROR_UNSUPPORTED_MODE,
3209  "nval = %d", nval );
3210  /* nval used in FLAMES code are 32, 48, 64 and 80 */
3211 
3212 
3213  strncpy(val, values, 16);
3214  val[16] = '\0';
3215  returnvalue = flames_midas_scdwrc(id, "BUNIT", 1, val, felem, 16, unit);
3216 
3217  for (i = 1; i < nval/16; i++) {
3218  const char *ctype_i;
3219 
3220  switch(i) {
3221  case 1: ctype_i = "CTYPE1"; break;
3222  case 2: ctype_i = "CTYPE2"; break;
3223  case 3: ctype_i = "CTYPE3"; break;
3224  case 4: ctype_i = "CTYPE4"; break;
3225  default:
3226  return 1;
3227  break;
3228  }
3229 
3230  strncpy(val, values+i*16, 16);
3231  val[16] = '\0';
3232 
3233  if (returnvalue == 0) {
3234  returnvalue = flames_midas_scdwrc(id, ctype_i, 1, val, felem, 16, unit);
3235  }
3236  }
3237  }
3238  else {
3239  /* The FLAMES C code has only one call like this.
3240  Implement it by 3 manual calls.
3241  */
3242  assure( nval == 3, CPL_ERROR_UNSUPPORTED_MODE,
3243  "noelm = %d, nval = %d", noelm, nval);
3244 
3245  /* Yes, here noelm and nval are swapped */
3246  returnvalue = flames_midas_scdwrc(id, "BUNIT", 1, values+0, felem, noelm, unit);
3247  if (returnvalue == 0) {
3248  returnvalue = flames_midas_scdwrc(id, "CTYPE1", 1, values+1, felem, noelm, unit);
3249  }
3250  if (returnvalue == 0) {
3251  returnvalue = flames_midas_scdwrc(id, "CTYPE2", 1, values+2, felem, noelm, unit);
3252  }
3253  }
3254  }
3255  else {
3256  assure( noelm == sizeof(char), CPL_ERROR_UNSUPPORTED_MODE, "Implement me" );
3257  assure( felem == 1, CPL_ERROR_UNSUPPORTED_MODE, "Implement me" );
3258 
3259  /* nval is the string length */
3260  tmp_string=cpl_calloc((nval+1),sizeof(char));
3261  strncpy(tmp_string,values,nval);
3262  returnvalue = scdwr('C', id, descr, tmp_string, felem, nval, unit);
3263 
3264  }
3265 
3266  cleanup:
3267  cpl_free(tmp_string);
3268  return returnvalue;
3269 }
3270 
3271 /*----------------------------------------------------------------------------*/
3278 /*----------------------------------------------------------------------------*/
3279 int flames_midas_scddel(int id, const char *descr)
3280 {
3281  cpl_property **cards = NULL;
3282  char type;
3283  int length, bytelem;
3284  const char *fits_descr = NULL;
3285  const char *name_regexp = NULL;
3286 
3287  passure( invariant(id), " ");
3288 
3289  assure( frame_is_open(id), CPL_ERROR_ILLEGAL_INPUT,
3290  "Frame no. %d is not open", id );
3291 
3292  /* Need to convert from MIDAS names to CPL propertylist names */
3293  check( cards = get_descr_info(id, descr, &type,
3294  &length, &bytelem),
3295  "Could not get info on descriptor %s", descr);
3296 
3297  if (cards != NULL)
3298  {
3299  int i;
3300 
3301  frames[id].need_to_save = true;
3302 
3303  for (i = 1; i <= length; i++)
3304  {
3305  int invert = 0;
3306  uves_free_string_const(&fits_descr);
3307  check( fits_descr = convert_to_fits(descr, i),
3308  "Could not convert %s to FITS", descr);
3309 
3310  /* uves_propertylist_erase() will erase only the first
3311  property with the given name. We want to erase all matches
3312  */
3313 
3314  uves_free_string_const(&fits_descr);
3315  name_regexp = uves_sprintf("^%s$", fits_descr);
3316  uves_propertylist_erase_regexp(frames[id].header, name_regexp, invert);
3317  }
3318  }
3319 
3320  passure( invariant(id), " ");
3321 
3322  cleanup:
3323  uves_free_string_const(&fits_descr);
3324  uves_free_string_const(&name_regexp);
3325  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3326 }
3327 
3328 /*----------------------------------------------------------------------------*/
3349 /*----------------------------------------------------------------------------*/
3350 
3351 static int scdcop(int from, int to, int mask, bool copy_naxis)
3352 {
3353  const char *key = NULL;
3354  passure( invariant(from), " ");
3355  passure( invariant(to ), " ");
3356 
3357  assure( frame_is_open(from), CPL_ERROR_ILLEGAL_INPUT,
3358  "Image no. %d is not open", from);
3359 
3360  assure( frame_is_open(to), CPL_ERROR_ILLEGAL_INPUT,
3361  "Image no. %d is not open", to);
3362 
3363  check( load_frame_header(from),
3364  "Could not load header of file %s", frames[from].filename);
3365 
3366  check( load_frame_header(to),
3367  "Could not load header of file %s", frames[to].filename);
3368 
3369  switch (mask) {
3370  case 1:
3371  /* copy all */
3372  if (0)
3373  {
3374  /* This would just append */
3375  uves_propertylist_append(frames[to].header, frames[from].header);
3376  }
3377  else
3378  {
3379  /* overwrites existing descriptors */
3380  if (copy_naxis) {
3381  uves_propertylist_copy_property_regexp(frames[to].header,
3382  frames[from].header,
3383  ".*", 0);
3384  }
3385  else {
3386  uves_propertylist_copy_property_regexp(frames[to].header,
3387  frames[from].header,
3388  "^NAXIS", 1);
3389  }
3390  }
3391  uves_msg_debug("%s header now contains %ld descriptors",
3392  frames[to].filename, uves_propertylist_get_size(frames[to].header));
3393 
3394  break;
3395  case 3:
3396  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
3397  break;
3398  default:
3399  /* Not needed for FLAMES code */
3400  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
3401  }
3402 
3403  /* Need to change size of image */
3404  if (frames[from].is_image && copy_naxis) {
3405  int naxis = uves_propertylist_get_int(frames[from].header, "NAXIS");
3406  int axis;
3407  int unit;
3408  int n[2];
3409 
3410  uves_msg_debug("Manually propagating NPIX");
3411 
3412  assure( naxis == 2, CPL_ERROR_UNSUPPORTED_MODE,
3413  "NAXIS = %d", naxis );
3414 
3415  for (axis = 1; axis <= naxis; axis++) {
3416  uves_free_string_const(&key);
3417  key = uves_sprintf("NAXIS%d", axis);
3418  n[axis-1] = uves_propertylist_get_int(frames[from].header, key);
3419  }
3420 
3421  check_nomsg( flames_midas_scdwri(to, "NPIX", n,
3422  1, 2, &unit));
3423  }
3424 
3425  frames[to].need_to_save = true;
3426  check( load_frame(to),
3427  "Could not load image %s", frames[to].filename);
3428 
3429  passure( invariant(from), " ");
3430  passure( invariant(to ), " ");
3431 
3432  cleanup:
3433  uves_free_string_const(&key);
3434  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3435 }
3436 
3437 /*----------------------------------------------------------------------------*/
3444 /*----------------------------------------------------------------------------*/
3445 int flames_midas_scdcop(int from, int to, int mask)
3446 {
3447  return scdcop(from, to, mask, true);
3448 }
3449 
3450 /*----------------------------------------------------------------------------*/
3457 /*----------------------------------------------------------------------------*/
3458 int flames_midas_scdcop_nonaxis(int from, int to, int mask)
3459 {
3460  return scdcop(from, to, mask, false);
3461 }
3462 
3463 /*----------------------------------------------------------------------------*/
3474 /*----------------------------------------------------------------------------*/
3475 int flames_midas_sccsho(const cpl_frameset *catfile,
3476  int *noent,
3477  int *last)
3478 {
3479  *last=*last; //to remove compilation warning: this is not used
3480  assure_nomsg( catfile != NULL, CPL_ERROR_NULL_INPUT );
3481  assure_nomsg( noent != NULL, CPL_ERROR_NULL_INPUT );
3482 
3483  *noent = cpl_frameset_get_size(catfile);
3484 
3485  //fixme: is 'last' used by any caller? If so, how is it different from 'noent'?
3486 
3487  cleanup:
3488  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3489 }
3490 
3491 
3492 /*----------------------------------------------------------------------------*/
3500 /*----------------------------------------------------------------------------*/
3501 int flames_midas_sccfnd(const cpl_frameset *catfile,
3502  int frmno,
3503  char *frame)
3504 {
3505  const cpl_frame *f;
3506 
3507  assure_nomsg( catfile != NULL, CPL_ERROR_NULL_INPUT );
3508  assure_nomsg( frame != NULL, CPL_ERROR_NULL_INPUT );
3509  frame[0] = '\0';
3510 
3511  check( f = cpl_frameset_get_frame_const(catfile, frmno-1), /* CPL counts from zero */
3512  "Could not get frame no. %d from catalog", frmno);
3513 
3514  strcpy(frame, cpl_frame_get_filename(f));
3515 
3516  uves_msg_debug("Returning frame %s", cpl_frame_get_filename(f));
3517 
3518  cleanup:
3519  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3520 }
3521 /*----------------------------------------------------------------------------*/
3538 /*----------------------------------------------------------------------------*/
3539 int flames_midas_sccget(const cpl_frameset *catfile,
3540  int flag,
3541  char *name, char *ident,
3542  int *no)
3543 {
3544  const char *fits_descr = NULL;
3545  uves_propertylist *header = NULL;
3546 
3547  assure_nomsg( catfile != NULL, CPL_ERROR_NULL_INPUT );
3548  assure_nomsg( no != NULL, CPL_ERROR_NULL_INPUT );
3549  assure_nomsg( name != NULL, CPL_ERROR_NULL_INPUT );
3550  assure_nomsg( flag == 0 || ident != NULL, CPL_ERROR_NULL_INPUT );
3551 
3552  if (*no == cpl_frameset_get_size(catfile))
3553  {
3554  *name = ' ';
3555  *no += 1;
3556 
3557  uves_msg_debug("Returning frame ' '");
3558  }
3559  else
3560  {
3561  const cpl_frame *f;
3562  check( f = cpl_frameset_get_frame_const(catfile, *no),
3563  "Could not get frame no. %d from catalog", *no);
3564 
3565  *no += 1;
3566  strcpy(name, cpl_frame_get_filename(f));
3567 
3568  if (flag != 0) {
3569  const char *ident_value;
3570 
3571  check( header = uves_propertylist_load(name, 0),
3572  "Failed to load %s header", name);
3573 
3574  if (false) {
3575  check_nomsg( fits_descr = convert_to_fits(ident, 1) );
3576  }
3577  else {
3578  fits_descr = uves_sprintf("%s", "OBJECT");
3579  }
3580 
3581  if (uves_propertylist_contains(header, fits_descr)) {
3582  check_nomsg( ident_value =
3583  uves_propertylist_get_string(header, fits_descr));
3584  }
3585  else {
3586  ident_value = " ";
3587  }
3588 
3589 
3590  /* Unsafe by design of this function */
3591  strcpy(ident, ident_value);
3592 
3593  /* Pad with blanks until strlen = 40 */
3594  {
3595  int i;
3596  i = strlen(ident);
3597  while (i <= 39) {
3598  ident[i] = ' ';
3599  i++;
3600  }
3601  ident[i] = '\0';
3602  }
3603 
3604  uves_msg_debug("Returning ident '%s'", ident);
3605 
3606  /* previously
3607  strcpy(ident, cpl_frame_get_tag(f));
3608  */
3609  }
3610 
3611  uves_msg_debug("Returning frame %s", name);
3612  }
3613 
3614 
3615  cleanup:
3616  uves_free_propertylist(&header);
3617  uves_free_string_const(&fits_descr);
3618 
3619  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3620 }
3621 
3622 /*----------------------------------------------------------------------------*/
3635 /*----------------------------------------------------------------------------*/
3636 int flames_midas_scccre(cpl_frameset **catfile,
3637  int type,
3638  int flag)
3639 {
3640  assure_nomsg( catfile != NULL, CPL_ERROR_NULL_INPUT );
3641 
3642  /* These parameters always have these values in the FLAMES code */
3643  assure( type == F_IMA_TYPE, CPL_ERROR_UNSUPPORTED_MODE,
3644  "Implement me");
3645  assure(flag == 0, CPL_ERROR_UNSUPPORTED_MODE,
3646  "Implement me");
3647 
3648  *catfile = cpl_frameset_new();
3649 
3650  cleanup:
3651  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3652 }
3653 
3654 /*----------------------------------------------------------------------------*/
3667 /*----------------------------------------------------------------------------*/
3668 int flames_midas_sccadd(cpl_frameset *catfile,
3669  const char *name,
3670  const char *ident)
3671 {
3672  //const char *fits_descr = NULL;
3673  cpl_frame* frame = NULL;
3674  //uves_propertylist *header = NULL;
3675 
3676  assure_nomsg( catfile != NULL, CPL_ERROR_NULL_INPUT );
3677  assure_nomsg( name != NULL, CPL_ERROR_NULL_INPUT );
3678  assure_nomsg( ident != NULL, CPL_ERROR_NULL_INPUT );
3679 
3680  frame = cpl_frame_new();
3681  cpl_frame_set_filename(frame, name);
3682  cpl_frame_set_tag(frame, "dummy"); /* need for cpl_frameset_insert() */
3683  cpl_frameset_insert(catfile, frame);
3684 
3685  /* In principle, we should here update the
3686  OBJECT fits card with the provided ident string.
3687  However this ident string is always a blank.
3688  Therefore do not update OBJECT which is very difficult to do with CPL */
3689 
3690  {
3691  int i = 0;
3692  while(ident[i] != '\0') {
3693  assure( ident[i] == ' ', CPL_ERROR_UNSUPPORTED_MODE,
3694  "Blank ident string expected. Received '%s'",
3695  ident);
3696  i++;
3697  }
3698  }
3699 
3700  /* previously
3701  cpl_frame_set_tag(frame, ident);
3702  */
3703 
3704  cleanup:
3705  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3706 }
3707 
3708 /*----------------------------------------------------------------------------*/
3714 /*----------------------------------------------------------------------------*/
3715 static cpl_type
3716 table_dtype_to_cpltype(int dtype, int alen)
3717 {
3718  cpl_type type = CPL_TYPE_INVALID;
3719 
3720  /* Only these combinations are used in FLAMES code */
3721  assure( dtype == D_I4_FORMAT ||
3722  dtype == D_R8_FORMAT ||
3723  dtype == D_R4_FORMAT ||
3724  dtype == D_C_FORMAT, CPL_ERROR_UNSUPPORTED_MODE,
3725  "dtype = %d", dtype);
3726 
3727  assure( dtype == D_C_FORMAT || alen == 1, CPL_ERROR_UNSUPPORTED_MODE,
3728  "dtype = %d, alen = %d", dtype, alen);
3729 
3730  switch(dtype) {
3731  case D_I4_FORMAT: type = CPL_TYPE_INT; break;
3732  case D_R4_FORMAT: type = CPL_TYPE_FLOAT; break;
3733  case D_R8_FORMAT: type = CPL_TYPE_DOUBLE; break;
3734  case D_C_FORMAT: type = CPL_TYPE_STRING; break;
3735  default:
3736  /* impossible */
3737  passure( false, " ");
3738  break;
3739  }
3740 
3741  cleanup:
3742  return type;
3743 }
3744 
3745 /*----------------------------------------------------------------------------*/
3751 /*----------------------------------------------------------------------------*/
3752 static int
3753 sizeof_cpltype(cpl_type type)
3754 {
3755  switch(type) {
3756  /* These correspondences are documented in CPL */
3757  case CPL_TYPE_INT: return sizeof(int); break;
3758  case CPL_TYPE_FLOAT: return sizeof(float); break;
3759  case CPL_TYPE_DOUBLE: return sizeof(double); break;
3760  case CPL_TYPE_STRING: return sizeof(char); break;
3761  default:
3762  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
3763  "Cannot convert CPL type %s", uves_tostring_cpl_type(type));
3764  break;
3765  }
3766 
3767  cleanup:
3768  return 0;
3769 }
3770 
3771 /*----------------------------------------------------------------------------*/
3777 /*----------------------------------------------------------------------------*/
3778 static int
3780 {
3781  int dtype = -1;
3782 
3783  switch(type) {
3784  case CPL_TYPE_INT: dtype = D_I4_FORMAT; break;
3785  case CPL_TYPE_FLOAT: dtype = D_R4_FORMAT; break;
3786  case CPL_TYPE_DOUBLE: dtype = D_R8_FORMAT; break;
3787  case CPL_TYPE_STRING: dtype = D_C_FORMAT; break;
3788  default:
3789  assure( false, CPL_ERROR_UNSUPPORTED_MODE,
3790  "Cannot convert CPL type %s", uves_tostring_cpl_type(type));
3791  break;
3792  }
3793 
3794  cleanup:
3795  return dtype;
3796 }
3797 
3798 /*----------------------------------------------------------------------------*/
3805 /*----------------------------------------------------------------------------*/
3806 static const char *
3807 table_colname_from_number(int tid, int column)
3808 {
3809  const char *name = NULL;
3810 
3811  passure( invariant(tid), " ");
3812 
3813  assure( frame_is_open(tid) && !frames[tid].is_image, CPL_ERROR_ILLEGAL_INPUT,
3814  "Table %d is not open", tid);
3815 
3816  check( load_frame(tid), "Could not load table %s", frames[tid].filename);
3817 
3818  assure( 1 <= column && column <= cpl_table_get_nrow(frames[tid].data.table.colnames),
3819  CPL_ERROR_ACCESS_OUT_OF_RANGE,
3820  "Illegal column number %d. Table has %" CPL_SIZE_FORMAT " row(s)",
3821  column, cpl_table_get_nrow(frames[tid].data.table.colnames));
3822 
3823  name = cpl_table_get_string(frames[tid].data.table.colnames, COLNAME,
3824  column - 1);
3825 
3826  cleanup:
3827  return name;
3828 }
3829 
3830 /*----------------------------------------------------------------------------*/
3844 /*----------------------------------------------------------------------------*/
3845 int flames_midas_tctopn(const char *name, int mode, int allrow, int *tid)
3846 {
3847  assure( allrow == -1 || mode == F_O_MODE, CPL_ERROR_INCOMPATIBLE_INPUT,
3848  "allrow = %d, mode = %d", allrow, mode);
3849 
3850  if (mode == F_I_MODE || mode == F_IO_MODE || mode == F_O_MODE)
3851  {
3852  /* Find first open slot */
3853  int i;
3854  bool found = false;
3855  for (i = 0; !found && i < MAX_OPEN; i++)
3856  {
3857  if (! frame_is_open(i))
3858  {
3859  found = true;
3860  *tid = i;
3861 
3862  if (mode == F_I_MODE || mode == F_IO_MODE) /* Input */
3863  {
3864  frame_new_table(i, name, NULL, false,
3865  NULL, 0, NULL);
3866  }
3867  else if (mode == F_O_MODE) /* Output */
3868  {
3869  cpl_table *colnames = cpl_table_new(0);
3870  cpl_table_new_column(colnames,
3871  COLNAME, CPL_TYPE_STRING);
3872 
3873  frame_new_table(i, name, uves_propertylist_new(), true,
3874  cpl_table_new(allrow), 0, colnames);
3875 
3876  }
3877 
3878  uves_msg_debug("Opened table no. %d: %s",
3879  i, name);
3880  }
3881  }
3882 
3883  assure( found, CPL_ERROR_UNSUPPORTED_MODE,
3884  "Cannot open more than %d table files",
3885  MAX_OPEN);
3886  }
3887  else
3888  {
3889  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
3890  }
3891 
3892  passure( invariant(*tid), " ");
3893 
3894  cleanup:
3895  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3896 }
3897 
3898 /*----------------------------------------------------------------------------*/
3905 /*----------------------------------------------------------------------------*/
3907 {
3908  return frame_close(tid);
3909 }
3910 
3911 /*----------------------------------------------------------------------------*/
3925 /*----------------------------------------------------------------------------*/
3926 int flames_midas_tccser(int tid, const char *colref, int *column)
3927 {
3928  bool found;
3929  int i;
3930 
3931  passure( invariant(tid), " ");
3932 
3933  /* The MIDAS interface supports the following, but there is no reason
3934  to do that for the FLAMES code */
3935  assure( colref[0] != ':' &&
3936  colref[0] != '#', CPL_ERROR_UNSUPPORTED_MODE, "Illegal column name: %s",
3937  colref);
3938 
3939  assure( frame_is_open(tid) && !frames[tid].is_image, CPL_ERROR_ILLEGAL_INPUT,
3940  "Table %d is not open", tid);
3941 
3942  check( load_frame(tid), "Could not load table %s", frames[tid].filename);
3943 
3944  *column = -1;
3945  found = false;
3946  for (i = 0; i < cpl_table_get_nrow(frames[tid].data.table.colnames) && !found; i++)
3947  {
3948  const char *name = cpl_table_get_string(frames[tid].data.table.colnames, COLNAME, i);
3949  if (strcmp(name, colref) == 0)
3950  {
3951  *column = i + 1; /* counting from 1 */
3952  found = true;
3953  }
3954  }
3955 
3956  if (!found)
3957  {
3958  uves_msg_warning("Table %s has no column %s",
3959  frames[tid].filename, colref);
3960  }
3961 
3962  passure( invariant(tid), " ");
3963 
3964  cleanup:
3965  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3966 }
3967 
3968 /*----------------------------------------------------------------------------*/
3977 /*----------------------------------------------------------------------------*/
3978 int flames_midas_tciget(int tid, int *column, int *row)
3979 {
3980  //const char *name;
3981 
3982  passure( invariant(tid), " ");
3983 
3984  assure( frame_is_open(tid) && !frames[tid].is_image, CPL_ERROR_ILLEGAL_INPUT,
3985  "Table %d is not open", tid);
3986 
3987  check( load_frame(tid), "Could not load table %s", frames[tid].filename);
3988 
3989  *column = cpl_table_get_ncol(frames[tid].data.table.table) - 1;
3990  /* Return actual number of rows, not allocated */
3991  //*row = cpl_table_get_nrow(frames[tid].data.table.table);
3992  *row = frames[tid].data.table.maxrow;
3993 
3994  passure( invariant(tid), " ");
3995 
3996  cleanup:
3997  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
3998 }
3999 
4000 /*----------------------------------------------------------------------------*/
4013 /*----------------------------------------------------------------------------*/
4014 int flames_midas_tcbget(int tid, int column, int *dtype, int *items, int *bytes)
4015 {
4016  const char *colname;
4017 
4018  check_nomsg( colname = table_colname_from_number(tid, column) );
4019 
4021  cpl_table_get_column_type(frames[tid].data.table.table,
4022  colname)) );
4023 
4024  /* Note!
4025  This function is only used in flames_create_full_ordertable.c,
4026  so it only has to work in that case.
4027  */
4028 
4029  *items = 1;
4030 
4031  if (*dtype == D_C_FORMAT)
4032  {
4033  *bytes = 80 * sizeof_cpltype(
4034  table_dtype_to_cpltype(*dtype, *items) );
4035  }
4036  else
4037  {
4038  *bytes = (*items) * sizeof_cpltype(
4039  table_dtype_to_cpltype(*dtype, *items) );
4040  }
4041 
4042  cleanup:
4043  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4044 }
4045 
4046 /*----------------------------------------------------------------------------*/
4053 /*----------------------------------------------------------------------------*/
4054 int flames_midas_tcdget(int tid, int *store)
4055 {
4056  tid=tid; //to remove compilation warning: this is not used
4057  *store=*store; //to remove compilation warning: this is not used
4058  assure( false, CPL_ERROR_UNSUPPORTED_MODE, "Implement me");
4059  cleanup: return 1;
4060 }
4061 
4062 /*----------------------------------------------------------------------------*/
4071 /*----------------------------------------------------------------------------*/
4072 int flames_midas_tcfget(int tid, int column, char *form, int *dtype)
4073 {
4074  const char *colname;
4075  const char *format;
4076 
4077  check_nomsg( colname = table_colname_from_number(tid, column));
4078 
4080  cpl_table_get_column_type(frames[tid].data.table.table, colname)));
4081 
4082  check_nomsg( format = cpl_table_get_column_format(frames[tid].data.table.table, colname));
4083 
4084  strcpy(form, format);
4085 
4086  cleanup:
4087  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4088 }
4089 
4090 /*----------------------------------------------------------------------------*/
4098 /*----------------------------------------------------------------------------*/
4099 int flames_midas_tclget(int tid, int column, char *label)
4100 {
4101  const char *colname;
4102 
4103  label[0] = '\0';
4104  check_nomsg( colname = table_colname_from_number(tid, column));
4105 
4106  /* It's up to the caller to allocate enough space */
4107  strcpy(label, colname);
4108 
4109  cleanup:
4110  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4111 }
4112 
4113 /*----------------------------------------------------------------------------*/
4121 /*----------------------------------------------------------------------------*/
4122 int flames_midas_tcuget(int tid, int column, char *unit)
4123 {
4124  const char *colname;
4125  const char *u;
4126 
4127  unit[0] = '\0';
4128  //uves_msg("column=%s \n",column);
4129  check_nomsg( colname = table_colname_from_number(tid, column));
4130  check_nomsg( u = cpl_table_get_column_unit(frames[tid].data.table.table, colname));
4131  assure( u != NULL, CPL_ERROR_ILLEGAL_INPUT, "Column %s unit not set", colname);
4132 
4133  strcpy(unit, u);
4134 
4135  cleanup:
4136  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4137 }
4138 /*----------------------------------------------------------------------------*/
4147 /*----------------------------------------------------------------------------*/
4148 int flames_midas_tclser(int tid, const char *label, int *column)
4149 {
4150  /* This function seems to be the same as flames_midas_tccser(),
4151  except that
4152  flames_midas_tccser() is case sensitive and allows prefixing
4153  the column name with : or #
4154 
4155  But these subtle differences are not used by the FLAMES code, so
4156  just call that other function */
4157  return flames_midas_tccser(tid, label, column);
4158 }
4159 
4160 /*----------------------------------------------------------------------------*/
4178 /*----------------------------------------------------------------------------*/
4179 int flames_midas_tccini(int tid, int dtype, int alen,
4180  const char *form, const char *unit, const char *label,
4181  int *column)
4182 {
4183  cpl_type type;
4184 
4185  passure( invariant(tid), " ");
4186 
4187  assure( frame_is_open(tid) && !frames[tid].is_image, CPL_ERROR_ILLEGAL_INPUT,
4188  "Table %d is not open", tid);
4189 
4190  check( load_frame(tid), "Could not load table %s", frames[tid].filename);
4191 
4192  check_nomsg( type = table_dtype_to_cpltype(dtype, alen) );
4193 
4194  uves_msg_debug("Creating column %s (unit = %s, format = %s)",
4195  label, unit, form);
4196 
4197  /* Create the column */
4198  assure( !cpl_table_has_column(frames[tid].data.table.table, label),
4199  CPL_ERROR_ILLEGAL_OUTPUT,
4200  "Column %s already exists", label);
4201  cpl_table_new_column (frames[tid].data.table.table, label, type);
4202  cpl_table_set_column_format(frames[tid].data.table.table, label, form);
4203  cpl_table_set_column_unit (frames[tid].data.table.table, label, unit);
4204 
4205  /* Initialize column to avoid garbage (CPL doesn't initialize NULL elements) */
4206  switch(type) {
4207  case CPL_TYPE_INT : cpl_table_fill_invalid_int (frames[tid].data.table.table, label, -1); break;
4208  case CPL_TYPE_FLOAT : cpl_table_fill_invalid_float (frames[tid].data.table.table, label, -1); break;
4209  case CPL_TYPE_DOUBLE: cpl_table_fill_invalid_double(frames[tid].data.table.table, label, -1); break;
4210  case CPL_TYPE_STRING: /* Do nothing, already NULL */ break;
4211  default:
4212  passure( false, " " );
4213  break;
4214  }
4215 
4216  /* Update description of columns */
4217  *column = cpl_table_get_ncol(frames[tid].data.table.table) - 1;
4218  cpl_table_set_size (frames[tid].data.table.colnames, *column); /* This is O(n^2) in the number of
4219  columns (i.e. slow if there are
4220  many columns, but the CPL table
4221  handling is like that anyway. */
4222  cpl_table_set_string(frames[tid].data.table.colnames, COLNAME, *column-1, label);
4223 
4224  passure( invariant(tid), " ");
4225 
4226  cleanup:
4227  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4228 }
4229 
4230 /*----------------------------------------------------------------------------*/
4245 /*----------------------------------------------------------------------------*/
4246 static int
4247 tcerd(cpl_type type, int tid, int row, int column,
4248  void *value, int *null)
4249 {
4250  const char *colname;
4251  const char *val_str;
4252 
4253  check_nomsg( colname = table_colname_from_number(tid, column));
4254 
4255  /* Check disabled, allow type conversion
4256  assure( cpl_table_get_column_type(frames[tid].data.table.table, colname)
4257  == type, CPL_ERROR_TYPE_MISMATCH, "Column %s type is %s, type %s expected",
4258  colname, uves_tostring_cpl_type(cpl_table_get_column_type(frames[tid].data.table.table, colname)),
4259  uves_tostring_cpl_type(type) );
4260  */
4261 
4262  assure( 1 <= row && row <= cpl_table_get_nrow(frames[tid].data.table.table),
4263  CPL_ERROR_ACCESS_OUT_OF_RANGE,
4264  "Cannot read row %d of %" CPL_SIZE_FORMAT " row table",
4265  row, cpl_table_get_nrow(frames[tid].data.table.table));
4266 
4267  switch(type) {
4268  case CPL_TYPE_INT:
4269  ((int *)value)[0] = cpl_table_get(frames[tid].data.table.table,
4270  colname, row - 1,
4271  null);
4272  break;
4273  case CPL_TYPE_FLOAT:
4274  ((float *)value)[0] = cpl_table_get(frames[tid].data.table.table,
4275  colname, row - 1,
4276  null);
4277  break;
4278  case CPL_TYPE_DOUBLE:
4279  ((double *)value)[0] = cpl_table_get(frames[tid].data.table.table,
4280  colname, row - 1,
4281  null);
4282  break;
4283  case CPL_TYPE_STRING:
4284  val_str = cpl_table_get_string(frames[tid].data.table.table,
4285  colname, row - 1);
4286  if (val_str == NULL)
4287  {
4288  if (null != NULL) *null = 1;
4289  ((char *)value)[0] = '\0';
4290  }
4291  else
4292  {
4293  if (null != NULL) *null = 0;
4294  strcpy((char *)value, val_str);
4295  }
4296  break;
4297  default:
4298  assure( false, CPL_ERROR_INVALID_TYPE, "Type is %s", uves_tostring_cpl_type(type));
4299  break;
4300  }
4301 
4302  cleanup:
4303  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4304 }
4305 
4306 /*----------------------------------------------------------------------------*/
4313 /*----------------------------------------------------------------------------*/
4314 int flames_midas_tcerdc(int tid, int row, int column, char *values, int *null)
4315 {
4316  return tcerd(CPL_TYPE_STRING, tid, row, column, values, null);
4317 }
4318 
4319 /*----------------------------------------------------------------------------*/
4323 /*----------------------------------------------------------------------------*/
4324 int flames_midas_tcerdi(int tid, int row, int column, int *value, int *null)
4325 {
4326  return tcerd(CPL_TYPE_INT, tid, row, column, value, null);
4327 }
4328 
4329 /*----------------------------------------------------------------------------*/
4333 /*----------------------------------------------------------------------------*/
4334 int flames_midas_tcerdr(int tid, int row, int column, float *value, int *null)
4335 {
4336  return tcerd(CPL_TYPE_FLOAT, tid, row, column, value, null);
4337 }
4338 
4339 /*----------------------------------------------------------------------------*/
4343 /*----------------------------------------------------------------------------*/
4344 int flames_midas_tcerdd(int tid, int row, int column,
4345  double *value, int *null)
4346 {
4347  return tcerd(CPL_TYPE_DOUBLE, tid, row, column, value, null);
4348 }
4349 
4350 /*----------------------------------------------------------------------------*/
4362 /*----------------------------------------------------------------------------*/
4363 static int tcewr(cpl_type type, int tid, int row, int column, const void *value)
4364 {
4365  const char *colname;
4366 
4367  check_nomsg( colname = table_colname_from_number(tid, column));
4368 
4369  /* Check disabled, allow type mismatch and conversion (as in MIDAS)
4370  assure( cpl_table_get_column_type(frames[tid].data.table.table, colname)
4371  == type, CPL_ERROR_TYPE_MISMATCH, "Column %s has type %s; %s expected",
4372  colname, uves_tostring_cpl_type(cpl_table_get_column_type(frames[tid].data.table.table, colname)),
4373  uves_tostring_cpl_type(type) );
4374  */
4375 
4376  assure( row <= cpl_table_get_nrow(frames[tid].data.table.table),
4377  CPL_ERROR_ACCESS_OUT_OF_RANGE,
4378  "Cannot write row %d from %" CPL_SIZE_FORMAT " row table",
4379  row, cpl_table_get_nrow(frames[tid].data.table.table));
4380 
4381  if (row > frames[tid].data.table.maxrow) {
4382  frames[tid].data.table.maxrow = row;
4383  }
4384 
4385  switch(type) {
4386  case CPL_TYPE_INT:
4387  cpl_table_set(frames[tid].data.table.table, colname, row - 1, ((const int *)value)[0]);
4388  break;
4389  case CPL_TYPE_FLOAT:
4390  cpl_table_set(frames[tid].data.table.table, colname, row - 1, ((const float *)value)[0]);
4391  break;
4392  case CPL_TYPE_DOUBLE:
4393  cpl_table_set(frames[tid].data.table.table, colname, row - 1, ((const double *)value)[0]);
4394  break;
4395  case CPL_TYPE_STRING:
4396  cpl_table_set_string(frames[tid].data.table.table, colname, row - 1, (const char *)value);
4397  break;
4398  default:
4399  assure( false, CPL_ERROR_INVALID_TYPE, "Type is %s", uves_tostring_cpl_type(type));
4400  break;
4401  }
4402 
4403  cleanup:
4404  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4405 }
4406 
4407 /*----------------------------------------------------------------------------*/
4414 /*----------------------------------------------------------------------------*/
4415 int flames_midas_tcewrc(int tid, int row, int column, const char *value)
4416 {
4417  /* Write full string, including commas */
4418  return tcewr(CPL_TYPE_STRING, tid, row, column, value);
4419 }
4420 
4421 /*----------------------------------------------------------------------------*/
4425 /*----------------------------------------------------------------------------*/
4426 int flames_midas_tcewrd(int tid, int row, int column, const double *value)
4427 {
4428  return tcewr(CPL_TYPE_DOUBLE, tid, row, column, value);
4429 }
4430 
4431 /*----------------------------------------------------------------------------*/
4435 /*----------------------------------------------------------------------------*/
4436 int flames_midas_tcewri(int tid, int row, int column, const int *value)
4437 {
4438  return tcewr(CPL_TYPE_INT, tid, row, column, value);
4439 }
4440 /*----------------------------------------------------------------------------*/
4444 /*----------------------------------------------------------------------------*/
4445 int flames_midas_tcewrr(int tid, int row, int column, const float *value)
4446 {
4447  return tcewr(CPL_TYPE_FLOAT, tid, row, column, value);
4448 }
4449 
4450 /*----------------------------------------------------------------------------*/
4454 /*----------------------------------------------------------------------------*/
4455 static int
4456 tcard(cpl_type type, int tid, int row, int column,
4457  int index, int items, void *value)
4458 {
4459  assure( index == 1 && (
4460  type == CPL_TYPE_STRING ||
4461  items == 1),
4462  CPL_ERROR_UNSUPPORTED_MODE,
4463  "index, items = %d, %d", index, items);
4464 
4465  return tcerd(type, tid, row, column, value, NULL);
4466 
4467  cleanup:
4468  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4469 }
4470 
4471 /*----------------------------------------------------------------------------*/
4483 /*----------------------------------------------------------------------------*/
4484 int flames_midas_tcardc(int tid, int row, int col, int index, int items, char *value)
4485 {
4486  return tcard(CPL_TYPE_STRING, tid, row, col, index, items, value);
4487 }
4488 
4489 /*----------------------------------------------------------------------------*/
4500 /*----------------------------------------------------------------------------*/
4501 int flames_midas_tcardd(int tid, int row, int col, int index, int items, double *value)
4502 {
4503  return tcard(CPL_TYPE_DOUBLE, tid, row, col, index, items, value);
4504 }
4505 
4506 /*----------------------------------------------------------------------------*/
4510 /*----------------------------------------------------------------------------*/
4511 int flames_midas_tcardi(int tid, int row, int col, int index, int items, int *value)
4512 {
4513  return tcard(CPL_TYPE_INT, tid, row, col, index, items, value);
4514 }
4515 
4516 /*----------------------------------------------------------------------------*/
4520 /*----------------------------------------------------------------------------*/
4521 int flames_midas_tcardr(int tid, int row, int col, int index, int items, float *value)
4522 {
4523  return tcard(CPL_TYPE_FLOAT, tid, row, col, index, items, value);
4524 }
4525 
4526 
4527 /*----------------------------------------------------------------------------*/
4531 /*----------------------------------------------------------------------------*/
4532 static int
4533 tcawr(cpl_type type, int tid, int row, int col, int index, int items, const void *value)
4534 {
4535  assure( index == 1 && (
4536  type == CPL_TYPE_STRING ||
4537  items == 1),
4538  CPL_ERROR_UNSUPPORTED_MODE,
4539  "index, items = %d, %d", index, items);
4540 
4541  return tcewr(type, tid, row, col, value);
4542 
4543  cleanup:
4544  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4545 }
4546 
4547 /*----------------------------------------------------------------------------*/
4558 /*----------------------------------------------------------------------------*/
4559 int flames_midas_tcawrc(int tid, int row, int col, int index, int items, const char *value)
4560 {
4561  return tcawr(CPL_TYPE_STRING, tid, row, col, index, items, value);
4562 }
4563 /*----------------------------------------------------------------------------*/
4574 /*----------------------------------------------------------------------------*/
4575 int flames_midas_tcawrd(int tid, int row, int col, int index, int items, const double *value)
4576 {
4577  return tcawr(CPL_TYPE_DOUBLE, tid, row, col, index, items, value);
4578 }
4579 /*----------------------------------------------------------------------------*/
4583 /*----------------------------------------------------------------------------*/
4584 int flames_midas_tcawri(int tid, int row, int col, int index, int items, const int *value)
4585 {
4586  return tcawr(CPL_TYPE_INT, tid, row, col, index, items, value);
4587 }
4588 
4589 /*----------------------------------------------------------------------------*/
4593 /*----------------------------------------------------------------------------*/
4594 int flames_midas_tcawrr(int tid, int row, int col, int index, int items, const float *value)
4595 {
4596  return tcawr(CPL_TYPE_FLOAT, tid, row, col, index, items, value);
4597 }
4598 
4599 /*----------------------------------------------------------------------------*/
4607 /*----------------------------------------------------------------------------*/
4608 int flames_midas_tcsget(int tid, int row, int *value)
4609 {
4610  passure( invariant(tid), " ");
4611 
4612  assure( frame_is_open(tid) && !frames[tid].is_image, CPL_ERROR_ILLEGAL_INPUT,
4613  "Table %d is not open", tid);
4614 
4615  check( load_frame(tid), "Could not load table %s", frames[tid].filename);
4616 
4617  assure( 1 <= row && row <= cpl_table_get_nrow(frames[tid].data.table.table),
4618  CPL_ERROR_ACCESS_OUT_OF_RANGE,
4619  "Cannot read row %d of %" CPL_SIZE_FORMAT " row table %s", row,
4620  cpl_table_get_nrow(frames[tid].data.table.table),
4621  frames[tid].filename);
4622 
4623  *value = cpl_table_get_int(frames[tid].data.table.table,
4624  "Select",
4625  row - 1, NULL);
4626 
4627  cleanup:
4628  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4629 }
4630 
4631 /*----------------------------------------------------------------------------*/
4639 /*----------------------------------------------------------------------------*/
4640 int flames_midas_tcsput(int tid, int row, const int *value)
4641 {
4642  passure( invariant(tid), " ");
4643 
4644  assure( frame_is_open(tid) && !frames[tid].is_image, CPL_ERROR_ILLEGAL_INPUT,
4645  "Table %d is not open", tid);
4646 
4647  check( load_frame(tid), "Could not load table %s", frames[tid].filename);
4648 
4649  assure( 1 <= row && row <= cpl_table_get_nrow(frames[tid].data.table.table),
4650  CPL_ERROR_ACCESS_OUT_OF_RANGE,
4651  "Cannot write to row %d of %" CPL_SIZE_FORMAT " row table %s", row,
4652  cpl_table_get_nrow(frames[tid].data.table.table),
4653  frames[tid].filename);
4654 
4655  cpl_table_set_int(frames[tid].data.table.table, "Select", row - 1, *value);
4656 
4657 
4658  if (row > frames[tid].data.table.maxrow) {
4659  frames[tid].data.table.maxrow = row;
4660  }
4661  cleanup:
4662  return (cpl_error_get_code() == CPL_ERROR_NONE) ? 0 : 1;
4663 }
4664