1 /* Note: this file has been modified from its original form by the
2 Astrometry.net team. For details see http://astrometry.net */
3
4 /* $Id: qfits_table.c,v 1.20 2007/01/10 12:24:45 yjung Exp $
5 *
6 * This file is part of the ESO QFITS Library
7 * Copyright (C) 2001-2004 European Southern Observatory
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /*
25 * $Author: yjung $
26 * $Date: 2007/01/10 12:24:45 $
27 * $Revision: 1.20 $
28 * $Name: qfits-6_2_0 $
29 */
30
31 /*-----------------------------------------------------------------------------
32 Includes
33 -----------------------------------------------------------------------------*/
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <assert.h>
42 #include <math.h>
43
44 #include "qfits_config.h"
45 #include "qfits_table.h"
46 #include "qfits_float.h"
47 #include "qfits_std.h"
48 #include "qfits_byteswap.h"
49 #include "qfits_tools.h"
50 #include "qfits_time.h"
51 #include "qfits_rw.h"
52 #include "qfits_md5.h"
53 #include "qfits_error.h"
54 #include "qfits_memory.h"
55
56 /*-----------------------------------------------------------------------------
57 Define
58 -----------------------------------------------------------------------------*/
59
60 #define ELEMENT_MAX_DISPLAY_SIZE 50
61
62 /*-----------------------------------------------------------------------------
63 Function prototypes
64 -----------------------------------------------------------------------------*/
65
66 static char * qfits_bintable_field_to_string(const qfits_table *, int, int,int);
67 static char * qfits_asciitable_field_to_string(const qfits_table *, int, int,
68 int);
69 static char * qfits_build_format(const qfits_col *);
70 static int qfits_table_append_bin_xtension(FILE *, const qfits_table *,
71 const void **);
72 static int qfits_table_append_ascii_xtension(FILE *, const qfits_table *,
73 const void **);
74 static int qfits_table_append_data(FILE *, const qfits_table *, const void **);
75 static int qfits_table_get_field_size(int, const qfits_col *);
76 static char * qfits_strstrip(const char *);
77 static double qfits_str2dec(const char *, int);
78
79 /*----------------------------------------------------------------------------*/
80 /**
81 * @defgroup qfits_table FITS table handling
82 *
83 */
84 /*----------------------------------------------------------------------------*/
85 /**@{*/
86
87 /*-----------------------------------------------------------------------------
88 Function codes
89 -----------------------------------------------------------------------------*/
90
qfits_table_get_col(const qfits_table * t,int i)91 const qfits_col* qfits_table_get_col(const qfits_table* t, int i) {
92 return t->col + i;
93 }
94
qfits_table_copy(const qfits_table * t)95 qfits_table* qfits_table_copy(const qfits_table* t) {
96 qfits_table* dest = calloc(1, sizeof(qfits_table));
97 assert(dest);
98 memcpy(dest, t, sizeof(qfits_table));
99 dest->col = calloc(dest->nc, sizeof(qfits_col));
100 memcpy(dest->col, t->col, dest->nc * sizeof(qfits_col));
101 return dest;
102 }
103
104
105
qfits_is_table_header(const qfits_header * hdr)106 int qfits_is_table_header(const qfits_header* hdr) {
107 char* value;
108 int ttype;
109 char buf[FITS_LINESZ + 1];
110
111 ttype = QFITS_INVALIDTABLE;
112 value = qfits_header_getstr(hdr, "XTENSION");
113 if (!value)
114 return ttype;
115 qfits_pretty_string_r(value, buf);
116 value = buf;
117 if (!strcmp(value, "TABLE")) {
118 ttype = QFITS_ASCIITABLE;
119 } else if (!strcmp(value, "BINTABLE")) {
120 ttype = QFITS_BINTABLE;
121 }
122 return ttype;
123 }
124
125 /*----------------------------------------------------------------------------*/
126 /**
127 @brief Generate a default primary header to store tables
128 @return the header object
129 */
130 /*----------------------------------------------------------------------------*/
qfits_table_prim_header_default(void)131 qfits_header * qfits_table_prim_header_default(void)
132 {
133 qfits_header * fh;
134
135 fh = qfits_header_new();
136
137 qfits_header_append(fh, "SIMPLE", "T", "Standard FITS file", NULL);
138 qfits_header_append(fh, "BITPIX", "8", "ASCII or bytes array", NULL);
139 qfits_header_append(fh, "NAXIS", "0", "Minimal header", NULL);
140 qfits_header_append(fh, "EXTEND", "T", "There may be FITS ext", NULL);
141 qfits_header_append(fh, "END", NULL, NULL, NULL);
142
143 return fh;
144 }
145
146 /*----------------------------------------------------------------------------*/
147 /**
148 @brief Generate a default extension header to store tables
149 @return the header object
150 */
151 /*----------------------------------------------------------------------------*/
qfits_table_ext_header_default(const qfits_table * t)152 qfits_header * qfits_table_ext_header_default(const qfits_table * t)
153 {
154 qfits_header * fh;
155 qfits_col * curr_col;
156 char str_val[FITS_LINESZ];
157 char str_val2[FITS_LINESZ];
158 char * date;
159 int tab_width;
160 int col_pos;
161 int i;
162
163 /* Compute the table width */
164 if ((tab_width = qfits_compute_table_width(t)) == -1) {
165 qfits_error("cannot get the table width");
166 return NULL;
167 }
168
169 /* Create fits header */
170 if ((fh=qfits_header_new()) == NULL) {
171 qfits_error("cannot create new fits header");
172 return NULL;
173 }
174
175 /* Check the kind of table */
176 if (t->tab_t == QFITS_BINTABLE) {
177
178 /* Write extension header */
179 qfits_header_append(fh, "XTENSION", "BINTABLE",
180 "FITS Binary Table Extension", NULL);
181 qfits_header_append(fh, "BITPIX", "8", "8-bits character format", NULL);
182 qfits_header_append(fh, "NAXIS", "2","Tables are 2-D char. array",NULL);
183 sprintf(str_val, "%d", tab_width);
184 qfits_header_append(fh, "NAXIS1", str_val, "Bytes in row", NULL);
185 sprintf(str_val, "%d", (int)(t->nr));
186 qfits_header_append(fh, "NAXIS2", str_val, "No. of rows in table",NULL);
187 qfits_header_append(fh, "PCOUNT", "0", "Parameter count always 0",NULL);
188 qfits_header_append(fh, "GCOUNT", "1", "Group count always 1", NULL);
189 sprintf(str_val, "%d", (int)(t->nc));
190 qfits_header_append(fh, "TFIELDS", str_val, "No. of col in table",NULL);
191 /* Columns descriptors */
192 curr_col = t->col;
193 for (i=0; i<t->nc; i++) {
194 sprintf(str_val, "TFORM%d", i+1);
195 sprintf(str_val2, "'%s'", qfits_build_format(curr_col));
196 qfits_header_append(fh, str_val, str_val2, "Format of field", NULL);
197
198 sprintf(str_val, "TTYPE%d", i+1);
199 sprintf(str_val2, "%s", curr_col->tlabel);
200 qfits_header_append(fh, str_val, str_val2, "Field label", NULL);
201
202 if (strlen(curr_col->tunit)) {
203 sprintf(str_val, "TUNIT%d", i+1);
204 sprintf(str_val2, "%s", curr_col->tunit);
205 //printf("Setting '%s' = '%s'\n", str_val, str_val2);
206 qfits_header_append(fh, str_val, str_val2, "Physical unit of field",
207 NULL);
208 }
209 if (curr_col->zero_present) {
210 sprintf(str_val, "TZERO%d", i+1);
211 sprintf(str_val2, "%f", curr_col->zero);
212 qfits_header_append(fh, str_val, str_val2,
213 "NULL value is defined", NULL);
214 }
215 if (curr_col->scale_present) {
216 sprintf(str_val, "TSCAL%d", i+1);
217 sprintf(str_val2, "%f", curr_col->scale);
218 qfits_header_append(fh, str_val, str_val2, "Scaling applied",
219 NULL);
220 }
221 curr_col++;
222 }
223 qfits_header_append(fh,"ORIGIN","ESO-QFITS", "Written by QFITS", NULL);
224
225 date = qfits_get_datetime_iso8601();
226 sprintf(str_val, "'%s'", date);
227 qfits_header_append(fh, "DATE", str_val, "[UTC] Date of writing", NULL);
228 qfits_header_append(fh, "END", NULL, NULL, NULL);
229
230 } else if (t->tab_t == QFITS_ASCIITABLE) {
231
232 /* Write extension header */
233 qfits_header_append(fh, "XTENSION", "TABLE",
234 "FITS ASCII Table Extension", NULL);
235 qfits_header_append(fh, "BITPIX", "8", "8-bits character format", NULL);
236 qfits_header_append(fh, "NAXIS", "2", "ASCII table has 2 axes", NULL);
237
238 /* Fill the header */
239 sprintf(str_val, "%d", tab_width);
240 qfits_header_append(fh, "NAXIS1", str_val, "Characters in a row", NULL);
241 sprintf(str_val, "%d", (int)(t->nr));
242 qfits_header_append(fh, "NAXIS2", str_val, "No. of rows in table",NULL);
243 qfits_header_append(fh, "PCOUNT", "0", "No group parameters", NULL);
244 qfits_header_append(fh, "GCOUNT", "1", "Only one group", NULL);
245 sprintf(str_val, "%d", (int)(t->nc));
246 qfits_header_append(fh, "TFIELDS", str_val, "No. of col in table",NULL);
247 qfits_header_append(fh, "ORIGIN","ESO-QFITS","Written by QFITS",NULL);
248 date = qfits_get_datetime_iso8601();
249 sprintf(str_val, "'%s'", date);
250 qfits_header_append(fh, "DATE", str_val, "[UTC] Date of writing", NULL);
251
252 /* Columns descriptors */
253 curr_col = t->col;
254 col_pos = 1;
255 for (i=0; i<t->nc; i++) {
256 sprintf(str_val, "TTYPE%d", i+1);
257 sprintf(str_val2, "%s", curr_col->tlabel);
258 qfits_header_append(fh, str_val, str_val2, "Field label", NULL);
259
260 sprintf(str_val, "TFORM%d", i+1);
261 sprintf(str_val2, "'%s'", qfits_build_format(curr_col));
262 qfits_header_append(fh, str_val, str_val2, "Format of field", NULL);
263
264 sprintf(str_val, "TBCOL%d", i+1);
265 sprintf(str_val2, "%d", col_pos);
266 qfits_header_append(fh, str_val, str_val2,"Start column of field",
267 NULL);
268 col_pos += curr_col->atom_nb;
269
270 sprintf(str_val, "TUNIT%d", i+1);
271 sprintf(str_val2, "%s", curr_col->tunit);
272 qfits_header_append(fh, str_val, str_val2, "Physical unit of field",
273 NULL);
274 if (curr_col->zero_present) {
275 sprintf(str_val, "TZERO%d", i+1);
276 sprintf(str_val2, "%f", curr_col->zero);
277 qfits_header_append(fh, str_val, str_val2,
278 "NULL value is defined", NULL);
279 }
280 if (curr_col->scale_present) {
281 sprintf(str_val, "TSCAL%d", i+1);
282 sprintf(str_val2, "%f", curr_col->scale);
283 qfits_header_append(fh, str_val, str_val2, "Scaling applied",
284 NULL);
285 }
286 curr_col++;
287 }
288 qfits_header_append(fh, "END", NULL, NULL, NULL);
289
290 } else {
291 qfits_error("Table type not known");
292 qfits_header_destroy(fh);
293 return NULL;
294 }
295 return fh;
296 }
297
298 /*----------------------------------------------------------------------------*/
299 /**
300 @brief Table object constructor
301 @param filename Name of the FITS file associated to the table
302 @param table_type Type of the table (QFITS_ASCIITABLE or QFITS_BINTABLE)
303 @param table_width Width in bytes of the table
304 @param nb_cols Number of columns
305 @param nb_raws Number of raws
306 @return The table object
307 The columns are also allocated. The object has to be deallocated with
308 qfits_table_close()
309 */
310 /*----------------------------------------------------------------------------*/
qfits_table_new(const char * filename,int table_type,int table_width,int nb_cols,int nb_raws)311 qfits_table * qfits_table_new(
312 const char * filename,
313 int table_type,
314 int table_width,
315 int nb_cols,
316 int nb_raws)
317 {
318 qfits_table * qt;
319 qt = qfits_malloc(sizeof(qfits_table));
320 strcpy(qt->filename, filename);
321 qt->tab_t = table_type;
322 qt->nc = nb_cols;
323 qt->nr = nb_raws;
324 if (qt->nc)
325 qt->col = qfits_calloc(qt->nc, sizeof(qfits_col));
326 else
327 qt->col = NULL;
328 qt->tab_w = table_width;
329
330 return qt;
331 }
332
333 /*----------------------------------------------------------------------------*/
334 /**
335 @brief Fill a column object with some provided informations
336 @param qc Pointer to the column that has to be filled
337 @param unit Unit of the data
338 @param label Label of the column
339 @param disp Way to display the data
340 @param nullval Null value
341 @param atom_nb Number of atoms per field. According to the type, an atom
342 is a double, an int, a char, ...
343 @param atom_dec_nb Number of decimals as specified in TFORM
344 @param atom_size Size in bytes of the field for ASCII tables, and of
345 an atom for BIN tables. ASCII tables only contain 1
346 atom per field (except for A type where you can of
347 course have more than one char per field)
348 @param atom_type Type of data (11 types for BIN, 5 for ASCII)
349 @param zero_present Flag to use or not zero
350 @param zero Zero value
351 @param scale_present Flag to use or not scale
352 @param scale Scale value
353 @param offset_beg Gives the position of the column
354 @return -1 in error case, 0 otherwise
355 */
356 /*----------------------------------------------------------------------------*/
qfits_col_fill(qfits_col * qc,int atom_nb,int atom_dec_nb,int atom_size,tfits_type atom_type,const char * label,const char * unit,const char * nullval,const char * disp,int zero_present,float zero,int scale_present,float scale,int offset_beg)357 int qfits_col_fill(
358 qfits_col * qc,
359 int atom_nb,
360 int atom_dec_nb,
361 int atom_size,
362 tfits_type atom_type,
363 const char * label,
364 const char * unit,
365 const char * nullval,
366 const char * disp,
367 int zero_present,
368 float zero,
369 int scale_present,
370 float scale,
371 int offset_beg)
372 {
373 /* Number of atoms per column */
374 qc->atom_nb = atom_nb;
375
376 /* Number of decimals in a field in ASCII table (0 in BINTABLE) */
377 qc->atom_dec_nb = atom_dec_nb;
378
379 /* Size in bytes of an atom */
380 qc->atom_size = atom_size;
381
382 /* Data type in the column */
383 qc->atom_type = atom_type;
384
385 /* Label of the column */
386 strcpy(qc->tlabel, label);
387
388 /* Unit of the column data */
389 strcpy(qc->tunit, unit);
390
391 /* Null value*/
392 strcpy(qc->nullval, nullval);
393
394 /* How to display the data */
395 strcpy(qc->tdisp, disp);
396
397 /* Default values for zero and scales */
398 qc->zero_present = zero_present;
399 qc->scale_present = scale_present;
400 qc->zero = zero;
401 qc->scale = scale;
402
403 /* Number of bytes between two consecutive fields of the same column */
404 qc->off_beg = offset_beg;
405
406 /* A column is a priori readable */
407 qc->readable = 1;
408
409 return 0;
410 }
411
412 /*
413 Creates a qfits_table* from the given qfits_header.
414 Also requires the offset to the beginning of the data unit, and its size.
415 (eg, via qfits_get_datinfo)
416 The "filename" and "xtnum" args are purely for printing error messages.
417 (the filename is copied to the qfits_table object, though)
418 */
qfits_table_open2(const qfits_header * hdr,off_t offset_beg,size_t data_size,const char * filename,int xtnum)419 qfits_table * qfits_table_open2(const qfits_header* hdr, off_t offset_beg, size_t data_size,
420 const char* filename, int xtnum) {
421 qfits_table * tload;
422 qfits_col * curr_col;
423 char str_val[FITS_LINESZ+1];
424 char keyword[FITSVALSZ];
425 /* Table infos */
426 int table_type;
427 int nb_col;
428 int table_width;
429 int nb_rows;
430 /* Column infos */
431 char label[FITSVALSZ];
432 char unit[FITSVALSZ];
433 char disp[FITSVALSZ];
434 char nullval[FITSVALSZ];
435 int atom_nb;
436 int atom_dec_nb;
437 int atom_size;
438 tfits_type atom_type;
439 size_t theory_size;
440 int zero_present;
441 int scale_present;
442 float zero;
443 float scale;
444
445 /* For ASCII tables */
446 int col_pos;
447 int next_col_pos;
448
449 /* For X type */
450 int nb_bits;
451
452 int i;
453
454 /* Identify a table and get the table type : ASCII or BIN */
455 if ((table_type = qfits_is_table_header(hdr)) == QFITS_INVALIDTABLE) {
456 qfits_error("[%s] extension %d is not a table", filename, xtnum);
457 return NULL;
458 }
459
460 /* Get number of columns and allocate them: nc <-> TFIELDS */
461 nb_col = qfits_header_getint(hdr, "TFIELDS", -1);
462 if (nb_col == -1) {
463 qfits_error("cannot read TFIELDS in [%s]:[%d]", filename, xtnum);
464 return NULL;
465 }
466
467 /* Get the width in bytes of the table */
468 table_width = qfits_header_getint(hdr, "NAXIS1", -1);
469 if (table_width == -1) {
470 qfits_error("cannot read NAXIS1 in [%s]:[%d]", filename, xtnum);
471 return NULL;
472 }
473
474 /* Get the number of rows */
475 nb_rows = qfits_header_getint(hdr, "NAXIS2", -1);
476 if (nb_rows == -1) {
477 qfits_error("cannot read NAXIS2 in [%s]:[%d]", filename, xtnum);
478 return NULL;
479 }
480
481 /* Create the table object */
482 tload = qfits_table_new(filename, table_type, table_width, nb_col, nb_rows);
483
484 /* Loop on all columns and get column descriptions */
485 curr_col = tload->col;
486 for (i=0; i<tload->nc; i++) {
487 const char* nil = "";
488
489 /* label <-> TTYPE */
490 sprintf(keyword, "TTYPE%d", i+1);
491 qfits_header_getstr_pretty(hdr, keyword, label, nil);
492
493 /* unit <-> TUNIT */
494 sprintf(keyword, "TUNIT%d", i+1);
495 qfits_header_getstr_pretty(hdr, keyword, unit, nil);
496
497 /* disp <-> TDISP */
498 sprintf(keyword, "TDISP%d", i+1);
499 qfits_header_getstr_pretty(hdr, keyword, disp, nil);
500
501 /* nullval <-> TNULL */
502 sprintf(keyword, "TNULL%d", i+1);
503 qfits_header_getstr_pretty(hdr, keyword, nullval, nil);
504
505 /* atom_size, atom_nb, atom_dec_nb, atom_type <-> TFORM */
506 sprintf(keyword, "TFORM%d", i+1);
507 if (qfits_header_getstr_pretty(hdr, keyword, str_val, NULL)) {
508 qfits_error("cannot read [%s] in [%s]:[%d]", keyword, filename, xtnum);
509 qfits_table_close(tload);
510 return NULL;
511 }
512 /* Interpret the type in header */
513 if (qfits_table_interpret_type(str_val, &atom_nb, &atom_dec_nb, &atom_type, table_type) == -1) {
514 qfits_error("cannot interpret column type: %s", str_val);
515 qfits_table_close(tload);
516 return NULL;
517 }
518
519 /* Set atom_size */
520 switch (atom_type) {
521 case TFITS_BIN_TYPE_A:
522 case TFITS_BIN_TYPE_L:
523 case TFITS_BIN_TYPE_B:
524 atom_size = 1;
525 break;
526 case TFITS_BIN_TYPE_I:
527 atom_size = 2;
528 break;
529 case TFITS_BIN_TYPE_J:
530 case TFITS_BIN_TYPE_E:
531 case TFITS_ASCII_TYPE_I:
532 case TFITS_ASCII_TYPE_E:
533 case TFITS_ASCII_TYPE_F:
534 atom_size = 4;
535 break;
536 case TFITS_BIN_TYPE_C:
537 case TFITS_BIN_TYPE_P:
538 atom_size = 4;
539 atom_nb *= 2;
540 break;
541 case TFITS_BIN_TYPE_K:
542 case TFITS_BIN_TYPE_D:
543 case TFITS_ASCII_TYPE_D:
544 atom_size = 8;
545 break;
546 case TFITS_BIN_TYPE_M:
547 atom_size = 8;
548 atom_nb *= 2;
549 break;
550 case TFITS_BIN_TYPE_X:
551 atom_size = 1;
552 nb_bits = atom_nb;
553 atom_nb = (int)((nb_bits - 1)/ 8) + 1;
554 break;
555 case TFITS_ASCII_TYPE_A:
556 atom_size = atom_nb;
557 break;
558 default:
559 qfits_error("unrecognized type");
560 qfits_table_close(tload);
561 return NULL;
562 break;
563 }
564
565 /* zero <-> TZERO */
566 sprintf(keyword, "TZERO%d", i+1);
567 zero_present = 1;
568 zero = qfits_header_getdouble(hdr, keyword, HUGE_VAL);
569 if (zero == HUGE_VAL) {
570 zero = 0.0;
571 zero_present = 0;
572 }
573
574 /* scale <-> TSCAL */
575 sprintf(keyword, "TSCAL%d", i+1);
576 scale_present = 1;
577 scale = qfits_header_getdouble(hdr, keyword, HUGE_VAL);
578 if (scale == HUGE_VAL) {
579 scale = 1.0;
580 scale_present = 0;
581 }
582
583 /* Fill the current column object */
584 qfits_col_fill(curr_col, atom_nb, atom_dec_nb, atom_size, atom_type,
585 label, unit, nullval, disp, zero_present, zero, scale_present,
586 scale, offset_beg);
587
588 /* Compute offset_beg but for the last column */
589 if (i < tload->nc - 1) {
590 if (table_type == QFITS_ASCIITABLE) {
591 /* column width <-> TBCOLi and TBCOLi+1 */
592 sprintf(keyword, "TBCOL%d", i+1);
593 col_pos = qfits_header_getint(hdr, keyword, -1);
594 if (col_pos == -1) {
595 qfits_error("cannot read [%s] in [%s]", keyword, filename);
596 qfits_table_close(tload);
597 return NULL;
598 }
599
600 sprintf(keyword, "TBCOL%d", i+2);
601 next_col_pos = qfits_header_getint(hdr, keyword, -1);
602 if (next_col_pos == -1) {
603 qfits_error("cannot read [%s] in [%s]", keyword, filename);
604 qfits_table_close(tload);
605 return NULL;
606 }
607 offset_beg += (int)(next_col_pos - col_pos);
608
609 } else if (table_type == QFITS_BINTABLE) {
610 offset_beg += atom_nb * atom_size;
611 }
612 }
613 curr_col++;
614 }
615
616 /* Check that the theoretical data size is not far from the measured */
617 /* one by more than 2880 */
618 theory_size = (size_t)qfits_compute_table_width(tload) * (size_t)tload->nr;
619 if (data_size < theory_size) {
620 qfits_error("Inconsistent data sizes: found %i, expected %i.", data_size, theory_size);
621 qfits_table_close(tload);
622 return NULL;
623 }
624
625 /* Return */
626 return tload;
627 }
628
629 /*----------------------------------------------------------------------------*/
630 /**
631 @brief Free a FITS table and associated pointers
632 @param t qfits_table to free
633 @return void
634 Frees all memory associated to a qfits_table structure.
635 */
636 /*----------------------------------------------------------------------------*/
qfits_table_close(qfits_table * t)637 void qfits_table_close(qfits_table * t)
638 {
639 if (t==NULL) return;
640 if (t->nc>0) if (t->col!=NULL) qfits_free(t->col);
641 qfits_free(t);
642 return;
643 }
644
645 /*----------------------------------------------------------------------------*/
646 /**
647 @brief Extract data from a column in a FITS table
648 @param th Allocated qfits_table
649 @param colnum Number of the column to extract (from 0 to colnum-1)
650 @param selection boolean array to define the selected rows
651 @return unsigned char array
652
653 If selection is NULL, select the complete column.
654
655 Extract a column from a FITS table and return the data as a bytes
656 array. The returned array type and size are determined by the
657 column object in the qfits_table and by the selection parameter.
658
659 Returned array size in bytes is:
660 nbselected * col->natoms * col->atom_size
661
662 Numeric types are correctly understood and byte-swapped if needed,
663 to be converted to the local machine type.
664
665 NULL values have to be handled by the caller.
666
667 The returned object must be deallocated with qfits_free().
668 */
669 /*----------------------------------------------------------------------------*/
qfits_query_column(const qfits_table * th,int colnum,const int * selection)670 unsigned char * qfits_query_column(
671 const qfits_table * th,
672 int colnum,
673 const int * selection)
674 {
675 char * start;
676 qfits_col * col;
677 int field_size;
678 unsigned char * array;
679 unsigned char * r;
680 unsigned char * inbuf;
681 int table_width;
682 int nb_rows;
683 size_t size;
684 int i;
685
686 if (th->tab_w == -1) {
687 /* Compute the table width in bytes */
688 if ((table_width = qfits_compute_table_width(th)) == -1) {
689 qfits_error("cannot compute the table width");
690 return NULL;
691 }
692 } else table_width = th->tab_w;
693
694 /* Compute the number of selected rows */
695 nb_rows = 0;
696 if (selection == NULL) {
697 nb_rows = th->nr;
698 } else {
699 for (i=0; i<th->nr; i++) if (selection[i] == 1) nb_rows++;
700 }
701
702 /* Pointer to requested column */
703 col = th->col + colnum;
704
705 /* Test if column is empty */
706 if (nb_rows * col->atom_size * col->atom_nb == 0) col->readable = 0;
707
708 /* Test if column is readable */
709 if (col->readable == 0) return NULL;
710
711 /* Compute the size in bytes of one field stored in the file */
712 if ((field_size=qfits_table_get_field_size(th->tab_t,col))==-1) return NULL;
713
714 /* Load input file */
715 if ((start=qfits_falloc((char *)(th->filename), 0, &size))==NULL) {
716 qfits_error("cannot open table for query [%s]", th->filename);
717 return NULL;
718 }
719
720 /* Allocate data array */
721 array = qfits_malloc(nb_rows * field_size * sizeof(char));
722
723 /* Position the input pointer at the begining of the column data */
724 r = array;
725 inbuf = (unsigned char*)start + col->off_beg;
726
727 /* Copy the values in array */
728 if (selection == NULL) {
729 /* No selection : get the complete column */
730 for (i=0; i<th->nr; i++) {
731 /* Copy all atoms on this field into array */
732 memcpy(r, inbuf, field_size);
733 r += field_size;
734 /* Jump to next line */
735 inbuf += table_width;
736 }
737 } else {
738 /* Get only the selected rows */
739 for (i=0; i<th->nr; i++) {
740 if (selection[i] == 1) {
741 /* Copy all atoms on this field into array */
742 memcpy(r, inbuf, field_size);
743 r += field_size;
744 }
745 /* Jump to next line */
746 inbuf += table_width;
747 }
748 }
749 qfits_fdealloc(start, 0, size);
750
751 /* SWAP the bytes if necessary */
752 #ifndef WORDS_BIGENDIAN
753 if ((th->tab_t == QFITS_BINTABLE) && (col->atom_size > 1)) {
754 r = array;
755 for (i=0; i<nb_rows * col->atom_nb; i++) {
756 qfits_swap_bytes(r, col->atom_size);
757 r += col->atom_size;
758 }
759 }
760 #endif
761
762 /* Return allocated and converted array */
763 return array;
764 }
765
766 /*----------------------------------------------------------------------------*/
767 /**
768 @brief Extract consequtive values from a column in a FITS table
769 @param th Allocated qfits_table
770 @param colnum Number of the column to extract (from 0 to colnum-1)
771 @param start_ind Index of the first row (0 for the first)
772 @param nb_rows Number of rows to extract
773 @return unsigned char array
774 Does the same as qfits_query_column() but on a consequtive sequence of rows
775 Spares the overhead of the selection object allocation
776 The returned object must be deallocated with qfits_free().
777 */
778 /*----------------------------------------------------------------------------*/
qfits_query_column_seq(const qfits_table * th,int colnum,int start_ind,int nb_rows)779 unsigned char * qfits_query_column_seq(
780 const qfits_table * th,
781 int colnum,
782 int start_ind,
783 int nb_rows)
784 {
785 char * start;
786 qfits_col * col;
787 int field_size;
788 unsigned char * array;
789 unsigned char * r;
790 unsigned char * inbuf;
791 int table_width;
792 size_t size;
793 int i;
794
795 if (th->tab_w == -1) {
796 /* Compute the table width in bytes */
797 if ((table_width = qfits_compute_table_width(th)) == -1) {
798 qfits_error("cannot compute the table width");
799 return NULL;
800 }
801 } else table_width = th->tab_w;
802
803 /* Check the validity of start_ind and nb_rows */
804 if ((start_ind<0) || (start_ind+nb_rows>th->nr)) {
805 qfits_error("bad start index and number of rows");
806 return NULL;
807 }
808
809 /* Pointer to requested column */
810 col = th->col + colnum;
811
812 /* Test if column is empty */
813 if (nb_rows * col->atom_size * col->atom_nb == 0) col->readable = 0;
814
815 /* Test if column is readable */
816 if (col->readable == 0) return NULL;
817
818 /* Compute the size in bytes of one field stored in the file */
819 if ((field_size=qfits_table_get_field_size(th->tab_t,col))==-1) return NULL;
820
821 /* Load input file */
822 if ((start=qfits_falloc((char *)(th->filename), 0, &size))==NULL) {
823 qfits_error("cannot open table for query [%s]", th->filename);
824 return NULL;
825 }
826
827 /* Allocate data array */
828 array = qfits_malloc(nb_rows * field_size * sizeof(char));
829
830 /* Position the input pointer at the begining of the column data */
831 r = array;
832 inbuf = (unsigned char*)start + col->off_beg + table_width * start_ind;
833
834 /* Copy the values in array */
835 /* Get only the selected rows */
836 for (i=0; i<nb_rows; i++) {
837 /* Copy all atoms on this field into array */
838 memcpy(r, inbuf, field_size);
839 r += field_size;
840 /* Jump to next line */
841 inbuf += table_width;
842 }
843 qfits_fdealloc(start, 0, size);
844
845 /* SWAP the bytes if necessary */
846 #ifndef WORDS_BIGENDIAN
847 if ((th->tab_t == QFITS_BINTABLE) && (col->atom_size > 1)) {
848 r = array;
849 for (i=0; i<nb_rows * col->atom_nb; i++) {
850 qfits_swap_bytes(r, col->atom_size);
851 r += col->atom_size;
852 }
853 }
854 #endif
855
856 /* Return allocated and converted array */
857 return array;
858 }
859
860
861
862
qfits_query_column_seq_to_array_endian(const qfits_table * th,int colnum,int start_ind,const int * indices,int nb_rows,unsigned char * destination,int dest_stride,int swap_endian)863 static int qfits_query_column_seq_to_array_endian(
864 const qfits_table * th,
865 int colnum,
866 int start_ind,
867 const int* indices,
868 int nb_rows,
869 unsigned char* destination,
870 int dest_stride,
871 int swap_endian)
872 {
873 qfits_col * col;
874 int field_size;
875 unsigned char * r;
876 unsigned char * inbuf;
877 int table_width;
878 int i;
879 int do_swap;
880
881 int maxind;
882
883 char* freeaddr;
884 size_t freesize;
885
886 size_t mapoffset;
887 size_t maplen;
888
889 if (th->tab_w == -1) {
890 /* Compute the table width in bytes */
891 if ((table_width = qfits_compute_table_width(th)) == -1) {
892 qfits_error("cannot compute the table width");
893 return -1;
894 }
895 } else table_width = th->tab_w;
896
897 /* Check the validity of start_ind and nb_rows */
898 if ((start_ind<0) || (start_ind+nb_rows>th->nr)) {
899 qfits_error("bad start index and number of rows");
900 return -1;
901 }
902
903 /* Pointer to requested column */
904 col = th->col + colnum;
905
906 /* Test if column is empty */
907 if (nb_rows * col->atom_size * col->atom_nb == 0) col->readable = 0;
908
909 /* Test if column is readable */
910 if (col->readable == 0) return -1;
911
912 /* Compute the size in bytes of one field stored in the file */
913 if ((field_size=qfits_table_get_field_size(th->tab_t,col))==-1)
914 return -1;
915
916 /* Load input file */
917 if (indices) {
918 maxind = 0;
919 for (i=0; i<nb_rows; i++)
920 maxind = MAX(maxind, indices[i]);
921 } else
922 maxind = nb_rows - 1;
923
924 // these size_t casts are *essential* to avoid overflow in > 2GB files!
925 mapoffset = col->off_beg + (size_t)table_width * (size_t)start_ind;
926 // NOTE that this *isn't* (table_width * N) -- that can lead to trying to map
927 // beyond the end of the file!
928 maplen = (size_t)maxind * (size_t)table_width + (size_t)field_size;
929
930 //printf("opening %s: %zu + %zu (column offset = %i, width=%i, start_index=%i)\n", th->filename, mapoffset, maplen, col->off_beg, table_width, start_ind);
931
932 if ((inbuf = qfits_falloc2(th->filename, mapoffset, maplen,
933 &freeaddr, &freesize)) == NULL) {
934 qfits_error("cannot open table for reading column data [%s]", th->filename);
935 return -1;
936 }
937
938 /*
939 if ((start=qfits_falloc(th->filename, 0, &size))==NULL) {
940 qfits_error("cannot open table for query [%s]", th->filename);
941 return -1;
942 }
943 inbuf = (unsigned char*)start + col->off_beg + table_width * start_ind;
944 */
945
946 /* Position the input pointer at the begining of the column data */
947 r = destination;
948
949 do_swap = 0;
950 #ifndef WORDS_BIGENDIAN
951 if (swap_endian)
952 if ((th->tab_t == QFITS_BINTABLE) && (col->atom_size > 1))
953 do_swap = 1;
954 #endif
955
956 /* Copy the values in array */
957 /* Get only the selected rows */
958 for (i=0; i<nb_rows; i++) {
959 /* Copy all atoms on this field into array */
960 if (indices) {
961 memcpy(r, inbuf + (indices[i]*table_width), field_size);
962 } else {
963 memcpy(r, inbuf, field_size);
964 /* Jump to next line */
965 inbuf += table_width;
966 }
967
968 #ifndef WORDS_BIGENDIAN
969 if (do_swap) {
970 int j;
971 unsigned char* r2 = r;
972 for (j=0; j<col->atom_nb; j++) {
973 qfits_swap_bytes(r2, col->atom_size);
974 r2 += col->atom_size;
975 }
976 }
977 #endif
978
979 r += dest_stride;
980 }
981
982 //qfits_fdealloc(start, 0, size);
983 qfits_fdealloc2(freeaddr, freesize);
984
985 return 0;
986 }
987
988
qfits_query_column_seq_to_array(const qfits_table * th,int colnum,int start_ind,int nb_rows,unsigned char * destination,int dest_stride)989 int qfits_query_column_seq_to_array(
990 const qfits_table * th,
991 int colnum,
992 int start_ind,
993 int nb_rows,
994 unsigned char* destination,
995 int dest_stride)
996 {
997 return qfits_query_column_seq_to_array_endian(th, colnum, start_ind, NULL, nb_rows, destination, dest_stride, 1);
998 }
999
qfits_query_column_seq_to_array_inds(const qfits_table * th,int colnum,const int * indices,int Ninds,unsigned char * destination,int dest_stride)1000 int qfits_query_column_seq_to_array_inds(const qfits_table * th,
1001 int colnum,
1002 const int* indices,
1003 int Ninds,
1004 unsigned char* destination,
1005 int dest_stride) {
1006 return qfits_query_column_seq_to_array_endian(th, colnum, 0, indices, Ninds, destination, dest_stride, 1);
1007 }
1008
qfits_query_column_seq_to_array_no_endian_swap(const qfits_table * th,int colnum,int start_ind,int nb_rows,unsigned char * destination,int dest_stride)1009 int qfits_query_column_seq_to_array_no_endian_swap(
1010 const qfits_table * th,
1011 int colnum,
1012 int start_ind,
1013 int nb_rows,
1014 unsigned char* destination,
1015 int dest_stride)
1016 {
1017 return qfits_query_column_seq_to_array_endian(th, colnum, start_ind, NULL, nb_rows, destination, dest_stride, 0);
1018 }
1019
1020 /*----------------------------------------------------------------------------*/
1021 /**
1022 @brief Extract binary data from a column in a FITS table
1023 @param th Allocated qfits_table
1024 @param colnum Number of the column to extract (from 0 to colnum-1)
1025 @param selection bollean array to identify selected rows
1026 @param null_value Value to return when a NULL value comes
1027 @return Pointer to void *
1028
1029 Extract a column from a FITS table and return the data as a generic
1030 void* array. The returned array type and size are determined by the
1031 column object in the qfits_table.
1032
1033 Returned array size in bytes is:
1034 nb_selected * col->atom_nb * col->atom_size
1035
1036 NULL values are recognized and replaced by the specified value.
1037 The returned object must be deallocated with qfits_free().
1038 */
1039 /*----------------------------------------------------------------------------*/
qfits_query_column_data(const qfits_table * th,int colnum,const int * selection,const void * null_value)1040 void * qfits_query_column_data(
1041 const qfits_table * th,
1042 int colnum,
1043 const int * selection,
1044 const void * null_value)
1045 {
1046 void * out_array;
1047 qfits_col * col;
1048 int nb_rows;
1049 unsigned char * in_array;
1050 char * field;
1051
1052 unsigned char ucnull;
1053 short snull;
1054 int inull;
1055 double dnull;
1056 float fnull;
1057
1058 int i;
1059
1060 /* Initialize */
1061 if (null_value == NULL) {
1062 inull = (int)0;
1063 snull = (short)0;
1064 ucnull = (unsigned char)0;
1065 fnull = (float)0.0;
1066 dnull = (double)0.0;
1067 } else {
1068 inull = *(int*)null_value;
1069 snull = *(short*)null_value;
1070 ucnull = *(unsigned char*)null_value;
1071 fnull = *(float*)null_value;
1072 dnull = *(double*)null_value;
1073 }
1074
1075 /* Get the number of selected rows */
1076 nb_rows = 0;
1077 if (selection == NULL) {
1078 nb_rows = th->nr;
1079 } else {
1080 for (i=0; i<th->nr; i++) if (selection[i] == 1) nb_rows++;
1081 }
1082
1083 /* Pointer to requested column */
1084 col = th->col+colnum;
1085
1086 /* Test if column is readable */
1087 if (col->readable == 0) return NULL;
1088
1089 /* Handle each type separately */
1090 switch(col->atom_type) {
1091 case TFITS_ASCII_TYPE_A:
1092 out_array = (char*)qfits_query_column(th, colnum, selection);
1093 break;
1094
1095 case TFITS_ASCII_TYPE_I:
1096 in_array = (unsigned char*)qfits_query_column(th, colnum, selection);
1097 out_array = qfits_malloc(nb_rows*col->atom_size);
1098 field = qfits_malloc((col->atom_nb+1)*sizeof(char));
1099 for (i=0; i<nb_rows; i++) {
1100 /* Copy all atoms of the field into 'field' */
1101 memcpy(field, &in_array[i*col->atom_nb], col->atom_nb);
1102 field[col->atom_nb]='\0';
1103 /* Write the data in out_array */
1104 /* Test if a NULL val is encoutered */
1105 if (!strcmp(col->nullval, qfits_strstrip(field))) {
1106 ((int*)out_array)[i] = inull;
1107 } else {
1108 ((int*)out_array)[i] = (int)atoi(field);
1109 }
1110 }
1111 qfits_free(field);
1112 qfits_free(in_array);
1113 break;
1114
1115 case TFITS_ASCII_TYPE_E:
1116 case TFITS_ASCII_TYPE_F:
1117 in_array = (unsigned char*)qfits_query_column(th, colnum, selection);
1118 out_array = qfits_malloc(nb_rows*col->atom_size);
1119 field = qfits_malloc((col->atom_nb+1)*sizeof(char));
1120 for (i=0; i<nb_rows; i++) {
1121 /* Copy all atoms of the field into 'field' */
1122 memcpy(field, &in_array[i*col->atom_nb], col->atom_nb);
1123 field[col->atom_nb]='\0';
1124 /* Write the data in out_array */
1125 /* Test if a NULL val is encoutered */
1126 if (!strcmp(col->nullval, qfits_strstrip(field))) {
1127 ((float*)out_array)[i] = fnull;
1128 } else {
1129 /* Add the decimal handling */
1130 ((float*)out_array)[i]=(float)qfits_str2dec(field,
1131 col->atom_dec_nb);
1132 }
1133 }
1134 qfits_free(field);
1135 qfits_free(in_array);
1136 break;
1137
1138 case TFITS_ASCII_TYPE_D:
1139 in_array = (unsigned char*)qfits_query_column(th, colnum, selection);
1140 out_array = qfits_malloc(nb_rows*col->atom_size);
1141 field = qfits_malloc((col->atom_nb+1)*sizeof(char));
1142 for (i=0; i<nb_rows; i++) {
1143 /* Copy all atoms of the field into 'field' */
1144 memcpy(field, &in_array[i*col->atom_nb], col->atom_nb);
1145 field[col->atom_nb]='\0';
1146 /* Write the data in out_array */
1147 /* Test if a NULL val is encoutered */
1148 if (!strcmp(col->nullval, field)) {
1149 ((double*)out_array)[i] = dnull;
1150 } else {
1151 /* Add the decimal handling */
1152 ((double*)out_array)[i]=qfits_str2dec(field, col->atom_dec_nb);
1153 }
1154 }
1155 qfits_free(field);
1156 qfits_free(in_array);
1157
1158 break;
1159 case TFITS_BIN_TYPE_A:
1160 case TFITS_BIN_TYPE_L:
1161 out_array = (char*)qfits_query_column(th, colnum, selection);
1162 break;
1163
1164 case TFITS_BIN_TYPE_D:
1165 case TFITS_BIN_TYPE_M:
1166 out_array = (double*)qfits_query_column(th, colnum, selection);
1167 for (i=0; i<nb_rows * col->atom_nb; i++) {
1168 if (qfits_isnan(((double*)out_array)[i]) ||
1169 qfits_isinf(((double*)out_array)[i])) {
1170 ((double*)out_array)[i] = dnull;
1171 }
1172 }
1173 break;
1174
1175 case TFITS_BIN_TYPE_E:
1176 case TFITS_BIN_TYPE_C:
1177 out_array = (float*)qfits_query_column(th, colnum, selection);
1178 for (i=0; i<nb_rows * col->atom_nb; i++) {
1179 if (qfits_isnan(((float*)out_array)[i]) ||
1180 qfits_isinf(((float*)out_array)[i])) {
1181 ((float*)out_array)[i] = fnull;
1182 }
1183 }
1184 break;
1185
1186 case TFITS_BIN_TYPE_X:
1187 out_array = (unsigned char*)qfits_query_column(th, colnum, selection);
1188 break;
1189
1190 case TFITS_BIN_TYPE_B:
1191 out_array = (unsigned char*)qfits_query_column(th, colnum, selection);
1192 for (i=0; i<nb_rows * col->atom_nb; i++) {
1193 if (((col->nullval)[0] != '\0') &&
1194 (atoi(col->nullval) == (int)((unsigned char*)out_array)[i])) {
1195 ((unsigned char*)out_array)[i] = ucnull;
1196 }
1197 }
1198 break;
1199
1200 case TFITS_BIN_TYPE_I:
1201 out_array = (short*)qfits_query_column(th, colnum, selection);
1202 for (i=0; i<nb_rows * col->atom_nb; i++) {
1203 if (((col->nullval)[0] != '\0') &&
1204 (atoi(col->nullval)==(int)((short*)out_array)[i])) {
1205 ((short*)out_array)[i] = snull;
1206 }
1207 }
1208 break;
1209
1210 case TFITS_BIN_TYPE_J:
1211 out_array = (int*)qfits_query_column(th, colnum, selection);
1212 for (i=0; i<nb_rows * col->atom_nb; i++) {
1213 if (((col->nullval)[0] != '\0') &&
1214 (atoi(col->nullval)==((int*)out_array)[i])) {
1215 ((int*)out_array)[i] = inull;
1216 }
1217 }
1218 break;
1219
1220 case TFITS_BIN_TYPE_K:
1221 out_array = (int64_t*)qfits_query_column(th, colnum, selection);
1222 for (i=0; i<nb_rows * col->atom_nb; i++) {
1223 if (((col->nullval)[0] != '\0') &&
1224 (atoll(col->nullval)==((int64_t*)out_array)[i])) {
1225 ((int64_t*)out_array)[i] = inull;
1226 }
1227 }
1228 break;
1229
1230 case TFITS_BIN_TYPE_P:
1231 out_array = (int*)qfits_query_column(th, colnum, selection);
1232 break;
1233
1234 default:
1235 qfits_error("unrecognized data type");
1236 return NULL;
1237 }
1238 return out_array;
1239 }
1240
1241 /*----------------------------------------------------------------------------*/
1242 /**
1243 @brief Extract binary data from a column in a FITS table
1244 @param th Allocated qfits_table
1245 @param colnum Number of the column to extract (from 0 to colnum-1)
1246 @param start_ind Index of the first row (0 for the first)
1247 @param nb_rows Number of rows to extract
1248 @param null_value Value to return when a NULL value comes
1249 @return Pointer to void *
1250 Does the same as qfits_query_column_data() but on a consequtive sequence
1251 of rows. Spares the overhead of the selection object allocation
1252 The returned object must be deallocated with qfits_free().
1253 */
1254 /*----------------------------------------------------------------------------*/
qfits_query_column_seq_data(const qfits_table * th,int colnum,int start_ind,int nb_rows,const void * null_value)1255 void * qfits_query_column_seq_data(
1256 const qfits_table * th,
1257 int colnum,
1258 int start_ind,
1259 int nb_rows,
1260 const void * null_value)
1261 {
1262 void * out_array;
1263 qfits_col * col;
1264 unsigned char * in_array;
1265 char * field;
1266
1267 unsigned char ucnull;
1268 short snull;
1269 int inull;
1270 double dnull;
1271 float fnull;
1272
1273 int i;
1274
1275 /* Initialize */
1276 if (null_value == NULL) {
1277 inull = (int)0;
1278 snull = (short)0;
1279 ucnull = (unsigned char)0;
1280 fnull = (float)0.0;
1281 dnull = (double)0.0;
1282 } else {
1283 inull = *(int*)null_value;
1284 snull = *(short*)null_value;
1285 ucnull = *(unsigned char*)null_value;
1286 fnull = *(float*)null_value;
1287 dnull = *(double*)null_value;
1288 }
1289
1290 /* Pointer to requested column */
1291 col = th->col+colnum;
1292
1293 /* Test if column is readable */
1294 if (col->readable == 0) return NULL;
1295
1296 /* Handle each type separately */
1297 switch(col->atom_type) {
1298 case TFITS_ASCII_TYPE_A:
1299 out_array = (char*)qfits_query_column_seq(th, colnum, start_ind,
1300 nb_rows);
1301 break;
1302
1303 case TFITS_ASCII_TYPE_I:
1304 in_array = (unsigned char*)qfits_query_column_seq(th, colnum,
1305 start_ind, nb_rows);
1306 out_array = qfits_malloc(nb_rows*col->atom_size);
1307 field = qfits_malloc((col->atom_nb+1)*sizeof(char));
1308 for (i=0; i<nb_rows; i++) {
1309 /* Copy all atoms of the field into 'field' */
1310 memcpy(field, &in_array[i*col->atom_nb], col->atom_nb);
1311 field[col->atom_nb]='\0';
1312 /* Write the data in out_array */
1313 /* Test if a NULL val is encoutered */
1314 if (!strcmp(col->nullval, qfits_strstrip(field))) {
1315 ((int*)out_array)[i] = inull;
1316 } else {
1317 ((int*)out_array)[i] = (int)atoi(field);
1318 }
1319 }
1320 qfits_free(field);
1321 qfits_free(in_array);
1322 break;
1323
1324 case TFITS_ASCII_TYPE_E:
1325 case TFITS_ASCII_TYPE_F:
1326 in_array = (unsigned char*)qfits_query_column_seq(th, colnum,
1327 start_ind, nb_rows);
1328 out_array = qfits_malloc(nb_rows*col->atom_size);
1329 field = qfits_malloc((col->atom_nb+1)*sizeof(char));
1330 for (i=0; i<nb_rows; i++) {
1331 /* Copy all atoms of the field into 'field' */
1332 memcpy(field, &in_array[i*col->atom_nb], col->atom_nb);
1333 field[col->atom_nb]='\0';
1334 /* Write the data in out_array */
1335 /* Test if a NULL val is encoutered */
1336 if (!strcmp(col->nullval, qfits_strstrip(field))) {
1337 ((float*)out_array)[i] = fnull;
1338 } else {
1339 /* Add the decimal handling */
1340 ((float*)out_array)[i]=(float)qfits_str2dec(field,
1341 col->atom_dec_nb);
1342 }
1343 }
1344 qfits_free(field);
1345 qfits_free(in_array);
1346 break;
1347
1348 case TFITS_ASCII_TYPE_D:
1349 in_array = (unsigned char*)qfits_query_column_seq(th, colnum,
1350 start_ind, nb_rows);
1351 out_array = qfits_malloc(nb_rows*col->atom_size);
1352 field = qfits_malloc((col->atom_nb+1)*sizeof(char));
1353 for (i=0; i<nb_rows; i++) {
1354 /* Copy all atoms of the field into 'field' */
1355 memcpy(field, &in_array[i*col->atom_nb], col->atom_nb);
1356 field[col->atom_nb]='\0';
1357 /* Write the data in out_array */
1358 /* Test if a NULL val is encoutered */
1359 if (!strcmp(col->nullval, qfits_strstrip(field))) {
1360 ((double*)out_array)[i] = dnull;
1361 } else {
1362 /* Add the decimal handling */
1363 ((double*)out_array)[i]=qfits_str2dec(field, col->atom_dec_nb);
1364 }
1365 }
1366 qfits_free(field);
1367 qfits_free(in_array);
1368 break;
1369
1370 case TFITS_BIN_TYPE_A:
1371 case TFITS_BIN_TYPE_L:
1372 out_array = (char*)qfits_query_column_seq(th, colnum,
1373 start_ind, nb_rows);
1374 break;
1375
1376 case TFITS_BIN_TYPE_D:
1377 case TFITS_BIN_TYPE_M:
1378 out_array = (double*)qfits_query_column_seq(th, colnum,
1379 start_ind, nb_rows);
1380 for (i=0; i<nb_rows * col->atom_nb; i++) {
1381 if (qfits_isnan(((double*)out_array)[i]) ||
1382 qfits_isinf(((double*)out_array)[i])) {
1383 ((double*)out_array)[i] = dnull;
1384 }
1385 }
1386 break;
1387
1388 case TFITS_BIN_TYPE_E:
1389 case TFITS_BIN_TYPE_C:
1390 out_array = (float*)qfits_query_column_seq(th, colnum,
1391 start_ind, nb_rows);
1392 for (i=0; i<nb_rows * col->atom_nb; i++) {
1393 if (qfits_isnan(((float*)out_array)[i]) ||
1394 qfits_isinf(((float*)out_array)[i])) {
1395 ((float*)out_array)[i] = fnull;
1396 }
1397 }
1398 break;
1399
1400 case TFITS_BIN_TYPE_X:
1401 out_array = (unsigned char*)qfits_query_column_seq(th, colnum,
1402 start_ind, nb_rows);
1403 break;
1404
1405 case TFITS_BIN_TYPE_B:
1406 out_array = (unsigned char*)qfits_query_column_seq(th, colnum,
1407 start_ind, nb_rows);
1408 for (i=0; i<nb_rows * col->atom_nb; i++) {
1409 if (((col->nullval)[0] != '\0') &&
1410 (atoi(col->nullval)== (int)((unsigned char*)out_array)[i])) {
1411 ((unsigned char*)out_array)[i] = ucnull;
1412 }
1413 }
1414 break;
1415
1416 case TFITS_BIN_TYPE_I:
1417 out_array = (short*)qfits_query_column_seq(th, colnum,
1418 start_ind, nb_rows);
1419 for (i=0; i<nb_rows * col->atom_nb; i++) {
1420 if (((col->nullval)[0] != '\0') &&
1421 (atoi(col->nullval)==(int)((short*)out_array)[i])) {
1422 ((short*)out_array)[i] = snull;
1423 }
1424 }
1425 break;
1426
1427 case TFITS_BIN_TYPE_J:
1428 out_array = (int*)qfits_query_column_seq(th, colnum,
1429 start_ind, nb_rows);
1430 for (i=0; i<nb_rows * col->atom_nb; i++) {
1431 if (((col->nullval)[0] != '\0') &&
1432 (atoi(col->nullval)==((int*)out_array)[i])) {
1433 ((int*)out_array)[i] = inull;
1434 }
1435 }
1436 break;
1437
1438 case TFITS_BIN_TYPE_K:
1439 out_array = (int64_t*)qfits_query_column_seq(th, colnum,
1440 start_ind, nb_rows);
1441 for (i=0; i<nb_rows * col->atom_nb; i++) {
1442 if (((col->nullval)[0] != '\0') &&
1443 (atoll(col->nullval)==((int64_t*)out_array)[i])) {
1444 ((int64_t*)out_array)[i] = inull;
1445 }
1446 }
1447 break;
1448
1449 case TFITS_BIN_TYPE_P:
1450 out_array = (int*)qfits_query_column_seq(th, colnum,
1451 start_ind, nb_rows);
1452 break;
1453
1454 default:
1455 qfits_error("unrecognized data type");
1456 return NULL;
1457 }
1458 return out_array;
1459 }
1460
1461 /*----------------------------------------------------------------------------*/
1462 /**
1463 @brief Detect NULL values in a column
1464 @param th Allocated qfits_table
1465 @param colnum Number of the column to check (from 0 to colnum-1)
1466 @param selection Array to identify selected rows
1467 @param nb_vals Gives the size of the output array
1468 @param nb_nulls Gives the number of detected null values
1469 @return array with 1 for NULLs and 0 for non-NULLs
1470 The returned object must be deallocated with qfits_free().
1471 */
1472 /*----------------------------------------------------------------------------*/
qfits_query_column_nulls(const qfits_table * th,int colnum,const int * selection,int * nb_vals,int * nb_nulls)1473 int * qfits_query_column_nulls(
1474 const qfits_table * th,
1475 int colnum,
1476 const int * selection,
1477 int * nb_vals,
1478 int * nb_nulls)
1479 {
1480 int * out_array;
1481 qfits_col * col;
1482 unsigned char * in_array;
1483 void * tmp_array;
1484 char * field;
1485 int nb_rows;
1486 int i;
1487
1488 /* Initialize */
1489 *nb_nulls = 0;
1490 *nb_vals = 0;
1491
1492 /* Get the number of selected rows */
1493 nb_rows = 0;
1494 if (selection == NULL) {
1495 nb_rows = th->nr;
1496 } else {
1497 for (i=0; i<th->nr; i++) if (selection[i] == 1) nb_rows++;
1498 }
1499
1500 /* Pointer to requested column */
1501 col = th->col+colnum;
1502
1503 /* Test if column is readable */
1504 if (col->readable == 0) return NULL;
1505
1506 /* Handle each type separately */
1507 switch(col->atom_type) {
1508 case TFITS_ASCII_TYPE_A:
1509 case TFITS_ASCII_TYPE_D:
1510 case TFITS_ASCII_TYPE_E:
1511 case TFITS_ASCII_TYPE_F:
1512 case TFITS_ASCII_TYPE_I:
1513 in_array = (unsigned char*)qfits_query_column(th, colnum, selection);
1514 out_array = qfits_calloc(nb_rows, sizeof(int));
1515 *nb_vals = nb_rows;
1516 field = qfits_malloc((col->atom_nb+1)*sizeof(char));
1517 for (i=0; i<nb_rows; i++) {
1518 /* Copy all atoms of the field into 'field' */
1519 memcpy(field, &in_array[i*col->atom_nb], col->atom_nb);
1520 field[col->atom_nb]='\0';
1521 /* Test if a NULL val is encoutered */
1522 if (!strcmp(col->nullval, qfits_strstrip(field))) {
1523 out_array[i] = 1;
1524 (*nb_nulls)++;
1525 }
1526 }
1527 qfits_free(field);
1528 if (in_array != NULL) qfits_free(in_array);
1529 break;
1530
1531 case TFITS_BIN_TYPE_A:
1532 /* No NULL values */
1533 out_array = qfits_calloc(nb_rows * col->atom_nb, sizeof(int));
1534 *nb_vals = nb_rows * col->atom_nb;
1535 break;
1536
1537 case TFITS_BIN_TYPE_L:
1538 case TFITS_BIN_TYPE_X:
1539 case TFITS_BIN_TYPE_P:
1540 /* No NULL values */
1541 out_array = qfits_calloc(nb_rows * col->atom_nb, sizeof(int));
1542 *nb_vals = nb_rows * col->atom_nb;
1543 break;
1544
1545 case TFITS_BIN_TYPE_D:
1546 case TFITS_BIN_TYPE_M:
1547 tmp_array = (double*)qfits_query_column(th, colnum, selection);
1548 out_array = qfits_calloc(nb_rows * col->atom_nb, sizeof(int));
1549 *nb_vals = nb_rows * col->atom_nb;
1550 for (i=0; i<nb_rows * col->atom_nb; i++) {
1551 if (qfits_isnan(((double*)tmp_array)[i]) ||
1552 qfits_isinf(((double*)tmp_array)[i])) {
1553 out_array[i] = 1;
1554 (*nb_nulls)++;
1555 }
1556 }
1557 if (tmp_array != NULL) qfits_free(tmp_array);
1558 break;
1559
1560 case TFITS_BIN_TYPE_E:
1561 case TFITS_BIN_TYPE_C:
1562 tmp_array = (float*)qfits_query_column(th, colnum, selection);
1563 out_array = qfits_calloc(nb_rows * col->atom_nb, sizeof(int));
1564 *nb_vals = nb_rows * col->atom_nb;
1565 for (i=0; i<nb_rows * col->atom_nb; i++) {
1566 if (qfits_isnan(((float*)tmp_array)[i]) ||
1567 qfits_isinf(((float*)tmp_array)[i])) {
1568 out_array[i] = 1;
1569 (*nb_nulls)++;
1570 }
1571 }
1572 if (tmp_array != NULL) qfits_free(tmp_array);
1573 break;
1574
1575 case TFITS_BIN_TYPE_B:
1576 tmp_array = (unsigned char*)qfits_query_column(th, colnum, selection);
1577 out_array = qfits_calloc(nb_rows * col->atom_nb, sizeof(int));
1578 *nb_vals = nb_rows * col->atom_nb;
1579 for (i=0; i<nb_rows * col->atom_nb; i++) {
1580 if (((col->nullval)[0] != '\0') &&
1581 (atoi(col->nullval)==(int)((unsigned char*)tmp_array)[i])) {
1582 out_array[i] = 1;
1583 (*nb_nulls)++;
1584 }
1585 }
1586 if (tmp_array != NULL) qfits_free(tmp_array);
1587 break;
1588
1589 case TFITS_BIN_TYPE_I:
1590 tmp_array = (short*)qfits_query_column(th, colnum, selection);
1591 out_array = qfits_calloc(nb_rows * col->atom_nb, sizeof(int));
1592 *nb_vals = nb_rows * col->atom_nb;
1593 for (i=0; i<nb_rows * col->atom_nb; i++) {
1594 if (((col->nullval)[0] != '\0') &&
1595 (atoi(col->nullval)==(int)((short*)tmp_array)[i])) {
1596 out_array[i] = 1;
1597 (*nb_nulls)++;
1598 }
1599 }
1600 if (tmp_array != NULL) qfits_free(tmp_array);
1601 break;
1602
1603 case TFITS_BIN_TYPE_K:
1604 tmp_array = (int64_t*)qfits_query_column(th, colnum, selection);
1605 out_array = calloc(nb_rows * col->atom_nb, sizeof(int64_t));
1606 *nb_vals = nb_rows * col->atom_nb;
1607 for (i=0; i<nb_rows * col->atom_nb; i++) {
1608 if (((col->nullval)[0] != '\0') &&
1609 (atoll(col->nullval)==((int64_t*)tmp_array)[i])) {
1610 out_array[i] = 1;
1611 (*nb_nulls)++;
1612 }
1613 }
1614 if (tmp_array != NULL) free(tmp_array);
1615 break;
1616
1617 case TFITS_BIN_TYPE_J:
1618 tmp_array = (int*)qfits_query_column(th, colnum, selection);
1619 out_array = qfits_calloc(nb_rows * col->atom_nb, sizeof(int));
1620 *nb_vals = nb_rows * col->atom_nb;
1621 for (i=0; i<nb_rows * col->atom_nb; i++) {
1622 if (((col->nullval)[0] != '\0') &&
1623 (atoi(col->nullval)==((int*)tmp_array)[i])) {
1624 out_array[i] = 1;
1625 (*nb_nulls)++;
1626 }
1627 }
1628 if (tmp_array != NULL) qfits_free(tmp_array);
1629 break;
1630
1631 default:
1632 qfits_error("unrecognized data type");
1633 return NULL;
1634 }
1635 return out_array;
1636 }
1637
1638
1639 /*----------------------------------------------------------------------------*/
1640 /**
1641 @brief Appends a std extension header + data to a FITS table file.
1642 @param outfile Pointer to (opened) file ready for writing.
1643 @param t Pointer to qfits_table
1644 @param data Table data to write
1645 @return int 0 if Ok, -1 otherwise
1646
1647 Dumps a FITS table to a file. The whole table described by qfits_table, and
1648 the data arrays contained in 'data' are dumped to the file. An extension
1649 header is produced with all keywords needed to describe the table, then the
1650 data is dumped to the file.
1651 The output is then padded to reach a multiple of 2880 bytes in size.
1652 Notice that no main header is produced, only the extension part.
1653 */
1654 /*----------------------------------------------------------------------------*/
qfits_table_append_xtension(FILE * outfile,const qfits_table * t,const void ** data)1655 int qfits_table_append_xtension(
1656 FILE * outfile,
1657 const qfits_table * t,
1658 const void ** data)
1659 {
1660 /* Append the extension */
1661 if (t->tab_t == QFITS_BINTABLE) {
1662 if (qfits_table_append_bin_xtension(outfile, t, data) == -1) {
1663 qfits_error("in writing fits table");
1664 return -1;
1665 }
1666 } else if (t->tab_t == QFITS_ASCIITABLE) {
1667 if (qfits_table_append_ascii_xtension(outfile, t, data) == -1) {
1668 qfits_error("in writing fits table");
1669 return -1;
1670 }
1671 } else {
1672 qfits_error("Unrecognized table type");
1673 return -1;
1674 }
1675 return 0;
1676 }
1677
1678 /*----------------------------------------------------------------------------*/
1679 /**
1680 @brief Appends a specified extension header + data to a FITS table file.
1681 @param outfile Pointer to (opened) file ready for writing.
1682 @param t Pointer to qfits_table
1683 @param data Table data to write
1684 @param hdr Specified extension header
1685 @return int 0 if Ok, -1 otherwise
1686
1687 Dumps a FITS table to a file. The whole table described by qfits_table, and
1688 the data arrays contained in 'data' are dumped to the file following the
1689 specified fits header.
1690 The output is then padded to reach a multiple of 2880 bytes in size.
1691 Notice that no main header is produced, only the extension part.
1692 */
1693 /*----------------------------------------------------------------------------*/
qfits_table_append_xtension_hdr(FILE * outfile,const qfits_table * t,const void ** data,const qfits_header * hdr)1694 int qfits_table_append_xtension_hdr(
1695 FILE * outfile,
1696 const qfits_table * t,
1697 const void ** data,
1698 const qfits_header * hdr)
1699 {
1700 /* Write the fits header in the file */
1701 if (qfits_header_dump(hdr, outfile) == -1) {
1702 qfits_error("cannot dump header in file");
1703 return -1;
1704 }
1705
1706 /* Append the data to the file */
1707 return qfits_table_append_data(outfile, t, data);
1708 }
1709
1710 /*----------------------------------------------------------------------------*/
1711 /**
1712 @brief given a col and a row, find out the string to write for display
1713 @param table table structure
1714 @param col_id col id (0 -> nbcol-1)
1715 @param row_id row id (0 -> nrow-1)
1716 @param use_zero_scale Flag to use or not zero and scale
1717 @return the string
1718
1719 This function is highly inefficient, it should not be used in loops to
1720 display a complete table. It is more to get one field from time to
1721 time, or for debugging puposes.
1722 The returned object must be deallocated with qfits_free().
1723 */
1724 /*----------------------------------------------------------------------------*/
qfits_table_field_to_string(const qfits_table * table,int col_id,int row_id,int use_zero_scale)1725 char * qfits_table_field_to_string(
1726 const qfits_table * table,
1727 int col_id,
1728 int row_id,
1729 int use_zero_scale)
1730 {
1731 char * str;
1732
1733 switch (table->tab_t) {
1734 case QFITS_BINTABLE:
1735 str = qfits_bintable_field_to_string(table, col_id, row_id,
1736 use_zero_scale);
1737 break;
1738
1739 case QFITS_ASCIITABLE:
1740 str = qfits_asciitable_field_to_string(table, col_id, row_id,
1741 use_zero_scale);
1742 break;
1743 default:
1744 qfits_error("Table type not recognized");
1745 return NULL;
1746 break;
1747 }
1748 return str;
1749 }
1750
1751 /**@}*/
1752
1753 /*----------------------------------------------------------------------------*/
1754 /**
1755 @brief Compute the table width in bytes from the columns infos
1756 @param th Allocated qfits_table
1757 @return the width (-1 in error case)
1758 */
1759 /*----------------------------------------------------------------------------*/
qfits_compute_table_width(const qfits_table * th)1760 int qfits_compute_table_width(const qfits_table * th)
1761 {
1762 int width;
1763 qfits_col * curr_col;
1764 int i;
1765
1766 /* Initialize */
1767 width = 0;
1768
1769 /* Loop on all columns and get column descriptions */
1770 curr_col = th->col;
1771 for (i=0; i<th->nc; i++) {
1772 if (th->tab_t == QFITS_ASCIITABLE) {
1773 width += curr_col->atom_nb;
1774 } else if (th->tab_t == QFITS_BINTABLE) {
1775 width += curr_col->atom_nb * curr_col->atom_size;
1776 }
1777 curr_col++;
1778 }
1779 return width;
1780 }
1781
1782 /*----------------------------------------------------------------------------*/
1783 /**
1784 @brief given a col and a row, find out the string to write for display
1785 @param table table structure
1786 @param col_id col id (0 -> nbcol-1)
1787 @param row_id row id (0 -> nrow-1)
1788 @param use_zero_scale Flag to use or not zero and scale
1789 @return the string to write
1790
1791 The returned object must be deallocated with qfits_free().
1792 ASCII tables specific
1793 */
1794 /*----------------------------------------------------------------------------*/
qfits_asciitable_field_to_string(const qfits_table * table,int col_id,int row_id,int use_zero_scale)1795 static char * qfits_asciitable_field_to_string(
1796 const qfits_table * table,
1797 int col_id,
1798 int row_id,
1799 int use_zero_scale)
1800 {
1801 qfits_col * col;
1802 char * ccol;
1803 int * icol;
1804 float * fcol;
1805 double * dcol;
1806 char ctmp[512];
1807 char * stmp;
1808 int field_size;
1809 void * field;
1810 int * selection;
1811
1812 /* Test inputs */
1813 if (table->tab_t != QFITS_ASCIITABLE) return NULL;
1814
1815 /* Initialize */
1816 ctmp[0] = '\0';
1817
1818 /* Set selection to select the requested row */
1819 selection = qfits_calloc(table->nr, sizeof(int));
1820 selection[row_id] = 1;
1821
1822 /* Load the column data */
1823 if ((field = qfits_query_column_data(table, col_id, selection,
1824 NULL)) == NULL) return NULL;
1825 qfits_free(selection);
1826
1827 /* Set reference to the column */
1828 col = table->col + col_id;
1829
1830 /* Compute field size and allocate stmp */
1831 if (col->atom_nb > ELEMENT_MAX_DISPLAY_SIZE) field_size = col->atom_nb + 1;
1832 else field_size = ELEMENT_MAX_DISPLAY_SIZE;
1833 stmp = qfits_malloc(field_size * sizeof(char));
1834 stmp[0] = '\0';
1835
1836 /* Get the string to write according to the type */
1837 switch(col->atom_type) {
1838 case TFITS_ASCII_TYPE_A:
1839 ccol = (char*)field;
1840 strncpy(ctmp, ccol, col->atom_nb);
1841 ctmp[col->atom_nb] = '\0';
1842 strcpy(stmp, ctmp);
1843 break;
1844
1845 case TFITS_ASCII_TYPE_I:
1846 icol = (int*)field;
1847 /* Two cases: use col->zero and col->scale or not */
1848 if (col->zero_present && col->scale_present && use_zero_scale) {
1849 sprintf(stmp, "%f", (float)(col->zero +
1850 (float)icol[0] * col->scale));
1851 } else {
1852 sprintf(stmp, "%d", icol[0]);
1853 }
1854 break;
1855
1856 case TFITS_ASCII_TYPE_E:
1857 case TFITS_ASCII_TYPE_F:
1858 fcol = (float*)field;
1859 /* Two cases: use col->zero and col->scale or not */
1860 if (col->zero_present && col->scale_present && use_zero_scale) {
1861 sprintf(stmp, "%f", (float)(col->zero +
1862 fcol[0] * col->scale));
1863 } else {
1864 sprintf(stmp, "%f", fcol[0]);
1865 }
1866 break;
1867
1868 case TFITS_ASCII_TYPE_D:
1869 dcol = (double*)field;
1870 /* Two cases: use col->zero and col->scale or not */
1871 if (col->zero_present && col->scale_present && use_zero_scale) {
1872 sprintf(stmp, "%f", (float)(col->zero +
1873 (float)dcol[0] * col->scale));
1874 } else {
1875 sprintf(stmp, "%g", dcol[0]);
1876 }
1877 break;
1878 default:
1879 qfits_warning("Type not recognized");
1880 break;
1881 }
1882
1883 /* Free and return */
1884 qfits_free(field);
1885 return stmp;
1886 }
1887
1888 /*----------------------------------------------------------------------------*/
1889 /**
1890 @brief Given a col and a row, find out the string to write for display
1891 @param table table structure
1892 @param col_id col id (0 -> nbcol-1)
1893 @param row_id row id (0 -> nrow-1)
1894 @param use_zero_scale Flag to use or not zero and scale
1895 @return the allocated string to write
1896
1897 The returned object must be deallocated with qfits_free().
1898 BIN tables specific
1899 */
1900 /*----------------------------------------------------------------------------*/
qfits_bintable_field_to_string(const qfits_table * table,int col_id,int row_id,int use_zero_scale)1901 static char * qfits_bintable_field_to_string(
1902 const qfits_table * table,
1903 int col_id,
1904 int row_id,
1905 int use_zero_scale)
1906 {
1907 qfits_col * col;
1908 unsigned char * uccol;
1909 char * ccol;
1910 int * icol;
1911 int64_t * kcol;
1912 short * scol;
1913 float * fcol;
1914 double * dcol;
1915 char ctmp[512];
1916 char * stmp;
1917 int field_size;
1918 void * field;
1919 int * selection;
1920
1921 int i;
1922
1923 /* Test inputs */
1924 if (table->tab_t != QFITS_BINTABLE) return NULL;
1925
1926 /* Initialize */
1927 ctmp[0] = '\0';
1928
1929 /* Set selection to select the requested row */
1930 selection = qfits_calloc(table->nr, sizeof(int));
1931 selection[row_id] = 1;
1932
1933 /* Load the data column */
1934 if ((field = qfits_query_column_data(table, col_id, selection,
1935 NULL)) == NULL) {
1936 qfits_free(selection);
1937 return NULL;
1938 }
1939 qfits_free(selection);
1940
1941 /* Set reference to the column */
1942 col = table->col + col_id;
1943
1944 /* Compute field size and allocate stmp */
1945 field_size = col->atom_nb * ELEMENT_MAX_DISPLAY_SIZE;
1946 stmp = qfits_malloc(field_size * sizeof(char));
1947 stmp[0] = '\0';
1948
1949 /* Get the string to write according to the type */
1950 switch(col->atom_type) {
1951 case TFITS_BIN_TYPE_A:
1952 ccol = (char*)field;
1953 strncpy(ctmp, ccol, col->atom_size * col->atom_nb);
1954 ctmp[col->atom_size*col->atom_nb] = '\0';
1955 strcpy(stmp, ctmp);
1956 break;
1957
1958 case TFITS_BIN_TYPE_B:
1959 uccol = (unsigned char*)field;
1960 /* Two cases: use col->zero and col->scale or not */
1961 if (col->zero_present && col->scale_present && use_zero_scale) {
1962 /* For each atom of the column */
1963 for (i=0; i<col->atom_nb-1; i++) {
1964 sprintf(ctmp, "%f, ", (float)(col->zero +
1965 (float)uccol[i] * col->scale));
1966 strcat(stmp, ctmp);
1967 }
1968 /* Handle the last atom differently: no ',' */
1969 sprintf(ctmp, "%f", (float)(col->zero +
1970 (float)uccol[col->atom_nb-1]*col->scale));
1971 strcat(stmp, ctmp);
1972 } else {
1973 /* For each atom of the column */
1974 for (i=0; i<col->atom_nb-1; i++) {
1975 sprintf(ctmp, "%d, ", (int)uccol[i]);
1976 strcat(stmp, ctmp);
1977 }
1978 /* Handle the last atom differently: no ',' */
1979 sprintf(ctmp,"%d",(int)uccol[col->atom_nb-1]);
1980 strcat(stmp, ctmp);
1981 }
1982 break;
1983
1984 case TFITS_BIN_TYPE_D:
1985 case TFITS_BIN_TYPE_M:
1986 dcol = (double*)field;
1987 /* Two cases: use col->zero and col->scale or not */
1988 if (col->zero_present && col->scale_present && use_zero_scale) {
1989 /* For each atom of the column */
1990 for (i=0; i<col->atom_nb-1; i++) {
1991 sprintf(ctmp, "%g, ", (double)((double)col->zero +
1992 dcol[i] * (double)col->scale));
1993 strcat(stmp, ctmp);
1994 }
1995 /* Handle the last atom differently: no ',' */
1996 sprintf(ctmp, "%g", (double)((double)col->zero +
1997 dcol[col->atom_nb-1] * (double)col->scale));
1998 strcat(stmp, ctmp);
1999 } else {
2000 /* For each atom of the column */
2001 for (i=0; i<col->atom_nb-1; i++) {
2002 sprintf(ctmp, "%g, ", dcol[i]);
2003 strcat(stmp, ctmp);
2004 }
2005 /* Handle the last atom differently: no ',' */
2006 sprintf(ctmp, "%g", dcol[col->atom_nb-1]);
2007 strcat(stmp, ctmp);
2008 }
2009 break;
2010
2011 case TFITS_BIN_TYPE_E:
2012 case TFITS_BIN_TYPE_C:
2013 fcol = (float*)field;
2014 /* Two cases: use col->zero and col->scale or not */
2015 if (col->zero_present && col->scale_present && use_zero_scale) {
2016 /* For each atom of the column */
2017 for (i=0; i<col->atom_nb-1; i++) {
2018 sprintf(ctmp, "%f, ", (float)(col->zero +
2019 (float)fcol[i] * col->scale));
2020 strcat(stmp, ctmp);
2021 }
2022 /* Handle the last atom differently: no ',' */
2023 sprintf(ctmp, "%f", (float)(col->zero +
2024 (float)fcol[col->atom_nb-1] * col->scale));
2025 strcat(stmp, ctmp);
2026 } else {
2027 /* For each atom of the column */
2028 for (i=0; i<col->atom_nb-1; i++) {
2029 sprintf(ctmp, "%f, ", fcol[i]);
2030 strcat(stmp, ctmp);
2031 }
2032 /* Handle the last atom differently: no ',' */
2033 sprintf(ctmp, "%f", fcol[col->atom_nb-1]);
2034 strcat(stmp, ctmp);
2035 }
2036 break;
2037
2038 case TFITS_BIN_TYPE_I:
2039 scol = (short*)field;
2040 /* Two cases: use col->zero and col->scale or not */
2041 if (col->zero_present && col->scale_present && use_zero_scale) {
2042 /* For each atom of the column */
2043 for (i=0; i<col->atom_nb-1; i++) {
2044 sprintf(ctmp, "%f, ", (float)(col->zero +
2045 (float)scol[i] * col->scale));
2046 strcat(stmp, ctmp);
2047 }
2048 /* Handle the last atom differently: no ',' */
2049 sprintf(ctmp, "%f", (float)(col->zero +
2050 (float)scol[col->atom_nb-1] * col->scale));
2051 strcat(stmp, ctmp);
2052 } else {
2053 /* For each atom of the column */
2054 for (i=0; i<col->atom_nb-1; i++) {
2055 sprintf(ctmp, "%d, ", (int)scol[i]);
2056 strcat(stmp, ctmp);
2057 }
2058 /* Handle the last atom differently: no ',' */
2059 sprintf(ctmp, "%d",(int)scol[col->atom_nb-1]);
2060 strcat(stmp, ctmp);
2061 }
2062 break;
2063
2064 case TFITS_BIN_TYPE_J:
2065 icol = (int*)field;
2066 /* Two cases: use col->zero and col->scale or not */
2067 if (col->zero_present && col->scale_present && use_zero_scale) {
2068 /* For each atom of the column */
2069 for (i=0; i<col->atom_nb-1; i++) {
2070 sprintf(ctmp, "%f, ", (float)(col->zero +
2071 (float)icol[i] * col->scale));
2072 strcat(stmp, ctmp);
2073 }
2074 /* Handle the last atom differently: no ',' */
2075 sprintf(ctmp, "%f", (float)(col->zero +
2076 (float)icol[col->atom_nb-1] * col->scale));
2077 strcat(stmp, ctmp);
2078 } else {
2079 /* For each atom of the column */
2080 for (i=0; i<col->atom_nb-1; i++) {
2081 sprintf(ctmp, "%d, ", (int)icol[i]);
2082 strcat(stmp, ctmp);
2083 }
2084 /* Handle the last atom differently: no ',' */
2085 sprintf(ctmp, "%d",(int)icol[col->atom_nb-1]);
2086 strcat(stmp, ctmp);
2087 }
2088 break;
2089
2090 case TFITS_BIN_TYPE_K:
2091 kcol = (int64_t*)field;
2092 /* Two cases: use col->zero and col->scale or not */
2093 if (col->zero_present && col->scale_present && use_zero_scale) {
2094 /* For each atom of the column */
2095 for (i=0; i<col->atom_nb-1; i++) {
2096 sprintf(ctmp, "%f, ", (float)(col->zero +
2097 (float)kcol[i] * col->scale));
2098 strcat(stmp, ctmp);
2099 }
2100 /* Handle the last atom differently: no ',' */
2101 sprintf(ctmp, "%f", (float)(col->zero +
2102 (float)kcol[col->atom_nb-1] * col->scale));
2103 strcat(stmp, ctmp);
2104 } else {
2105 /* For each atom of the column */
2106 for (i=0; i<col->atom_nb-1; i++) {
2107 sprintf(ctmp, "%lld, ", (long long int)kcol[i]);
2108 strcat(stmp, ctmp);
2109 }
2110 /* Handle the last atom differently: no ',' */
2111 sprintf(ctmp, "%lld", (long long int)kcol[col->atom_nb-1]);
2112 strcat(stmp, ctmp);
2113 }
2114 break;
2115
2116 case TFITS_BIN_TYPE_L:
2117 ccol = (char*)field;
2118 /* For each atom of the column */
2119 for (i=0; i<col->atom_nb-1; i++) {
2120 sprintf(ctmp, "%c, ", ccol[i]);
2121 strcat(stmp, ctmp);
2122 }
2123 /* Handle the last atom differently: no ',' */
2124 sprintf(ctmp, "%c", ccol[col->atom_nb-1]);
2125 strcat(stmp, ctmp);
2126 break;
2127
2128 case TFITS_BIN_TYPE_X:
2129 uccol = (unsigned char*)field;
2130 /* For each atom of the column */
2131 for (i=0; i<col->atom_nb-1; i++) {
2132 sprintf(ctmp, "%d, ", uccol[i]);
2133 strcat(stmp, ctmp);
2134 }
2135 /* Handle the last atom differently: no ',' */
2136 sprintf(ctmp, "%d", uccol[col->atom_nb-1]);
2137 strcat(stmp, ctmp);
2138 break;
2139
2140 case TFITS_BIN_TYPE_P:
2141 icol = (int*)field;
2142 /* For each atom of the column */
2143 for (i=0; i<col->atom_nb-1; i++) {
2144 sprintf(ctmp, "%d, ", (int)icol[i]);
2145 strcat(stmp, ctmp);
2146 }
2147 /* Handle the last atom differently: no ',' */
2148 sprintf(ctmp, "%d",(int)icol[col->atom_nb-1]);
2149 strcat(stmp, ctmp);
2150 break;
2151
2152 default:
2153 qfits_warning("Type not recognized");
2154 break;
2155 }
2156 qfits_free(field);
2157 return stmp;
2158 }
2159
2160 /*----------------------------------------------------------------------------*/
2161 /**
2162 @brief Remove blanks at the beginning and the end of a string.
2163 @param s String to parse.
2164 @return ptr to statically allocated string.
2165
2166 This function returns a pointer to a statically allocated string,
2167 which is identical to the input string, except that all blank
2168 characters at the end and the beg. of the string have been removed.
2169 Do not free or modify the returned string!
2170 Since the returned string is statically allocated, it will be modified at
2171 each function call (not re-entrant).
2172 */
2173 /*----------------------------------------------------------------------------*/
qfits_strstrip(const char * s)2174 static char * qfits_strstrip(const char * s)
2175 {
2176 static char l[1024+1];
2177 char * last;
2178
2179 if (s==NULL) return NULL;
2180
2181 while (isspace((int)*s) && *s) s++;
2182
2183 memset(l, 0, 1024+1);
2184 strcpy(l, s);
2185 last = l + strlen(l);
2186 while (last > l) {
2187 if (!isspace((int)*(last-1)))
2188 break;
2189 last --;
2190 }
2191 *last = '\0';
2192
2193 return (char*)l;
2194 }
2195
2196 /*----------------------------------------------------------------------------*/
2197 /**
2198 @brief Make a double out of a string and a number of decimals
2199 @param to_format the string to convert
2200 @param nb_dec the number of decimals
2201 @return the double
2202 A field with 123 of type F3.1 actually contains 12.3
2203 This is handled by this function.
2204 */
2205 /*----------------------------------------------------------------------------*/
qfits_str2dec(const char * to_format,int nb_dec)2206 static double qfits_str2dec(
2207 const char * to_format,
2208 int nb_dec)
2209 {
2210 double val;
2211 int i;
2212
2213 /* Test entries */
2214 if (to_format == NULL) return 0.00;
2215
2216 val = (double)atof(to_format);
2217 /* First handle case where there are no decimals or the dot is there */
2218 if ((strstr(to_format, ".") == NULL) && (nb_dec > 0)) {
2219 for (i=0; i<nb_dec; i++) val /=10;
2220 }
2221 return val;
2222 }
2223
2224 /*----------------------------------------------------------------------------*/
2225 /**
2226 @brief Parse a FITS type
2227 @param str string read in the FITS header (e.g. TFORM value)
2228 @param nb pointer to the number
2229 @param dec_nb pointer to the number of decimals
2230 @param type pointer to the type
2231 @param table_type Table type (BIN, ASCII, ...)
2232 @return 0 if ok, -1 otherwise
2233
2234 This functions reads the input string and uses it to update nb and type
2235 */
2236 /*----------------------------------------------------------------------------*/
qfits_table_interpret_type(const char * str,int * nb,int * dec_nb,tfits_type * type,int table_type)2237 int qfits_table_interpret_type(
2238 const char * str,
2239 int * nb,
2240 int * dec_nb,
2241 tfits_type * type,
2242 int table_type)
2243 {
2244 char type_c;
2245
2246 *dec_nb = 0;
2247 if (table_type == QFITS_BINTABLE) {
2248 if (sscanf(str, "%d%c", nb, &type_c) == 0) {
2249 /* nb is 1 by default */
2250 if (sscanf(str, "%c", &type_c) == 0) {
2251 qfits_error("cannot interpret this type: %s", str);
2252 return -1;
2253 }
2254 *nb = 1;
2255 }
2256 switch(type_c) {
2257 case 'A': *type = TFITS_BIN_TYPE_A; break;
2258 case 'B': *type = TFITS_BIN_TYPE_B; break;
2259 case 'C': *type = TFITS_BIN_TYPE_C; break;
2260 case 'D': *type = TFITS_BIN_TYPE_D; break;
2261 case 'E': *type = TFITS_BIN_TYPE_E; break;
2262 case 'I': *type = TFITS_BIN_TYPE_I; break;
2263 case 'J': *type = TFITS_BIN_TYPE_J; break;
2264 case 'K': *type = TFITS_BIN_TYPE_K; break;
2265 case 'L': *type = TFITS_BIN_TYPE_L; break;
2266 case 'M': *type = TFITS_BIN_TYPE_M; break;
2267 case 'P': *type = TFITS_BIN_TYPE_P; break;
2268 case 'X': *type = TFITS_BIN_TYPE_X; break;
2269 default: return -1;
2270 }
2271 } else if (table_type == QFITS_ASCIITABLE) {
2272 if (sscanf(str, "%c%d.%d", &type_c, nb, dec_nb) == 0) {
2273 qfits_error("cannot interpret this type: %s", str);
2274 return -1;
2275 }
2276 switch(type_c) {
2277 case 'A': *type = TFITS_ASCII_TYPE_A; break;
2278 case 'D': *type = TFITS_ASCII_TYPE_D; break;
2279 case 'E': *type = TFITS_ASCII_TYPE_E; break;
2280 case 'F': *type = TFITS_ASCII_TYPE_F; break;
2281 case 'I': *type = TFITS_ASCII_TYPE_I; break;
2282 default: return -1;
2283 }
2284 } else {
2285 qfits_error("unrecognized table type");
2286 return -1;
2287 }
2288 return 0;
2289 }
2290
2291 /*----------------------------------------------------------------------------*/
2292 /**
2293 @brief Generate a FITS type string
2294 @param col input column
2295 @return The string to write to TFORM
2296 */
2297 /*----------------------------------------------------------------------------*/
qfits_build_format(const qfits_col * col)2298 static char * qfits_build_format(const qfits_col * col)
2299 {
2300 static char sval[10];
2301 int nb;
2302
2303 switch (col->atom_type) {
2304 case TFITS_ASCII_TYPE_A:
2305 nb=sprintf(sval, "A%d.%d", col->atom_nb, col->atom_dec_nb); break;
2306 case TFITS_ASCII_TYPE_D:
2307 nb=sprintf(sval, "D%d.%d", col->atom_nb, col->atom_dec_nb); break;
2308 case TFITS_ASCII_TYPE_E:
2309 nb=sprintf(sval, "E%d.%d", col->atom_nb, col->atom_dec_nb); break;
2310 case TFITS_ASCII_TYPE_I:
2311 nb=sprintf(sval, "I%d.%d", col->atom_nb, col->atom_dec_nb); break;
2312 case TFITS_ASCII_TYPE_F:
2313 nb=sprintf(sval, "F%d.%d", col->atom_nb, col->atom_dec_nb); break;
2314 case TFITS_BIN_TYPE_D: nb=sprintf(sval, "%dD", col->atom_nb); break;
2315 case TFITS_BIN_TYPE_E: nb=sprintf(sval, "%dE", col->atom_nb); break;
2316 case TFITS_BIN_TYPE_I: nb=sprintf(sval, "%dI", col->atom_nb); break;
2317 case TFITS_BIN_TYPE_A: nb=sprintf(sval, "%dA", col->atom_nb); break;
2318 case TFITS_BIN_TYPE_B: nb=sprintf(sval, "%dB", col->atom_nb); break;
2319 case TFITS_BIN_TYPE_C: nb=sprintf(sval, "%dC",
2320 (int)(col->atom_nb/2)); break;
2321 case TFITS_BIN_TYPE_J: nb=sprintf(sval, "%dJ", col->atom_nb); break;
2322 case TFITS_BIN_TYPE_K: nb=sprintf(sval, "%dK", col->atom_nb); break;
2323 case TFITS_BIN_TYPE_L: nb=sprintf(sval, "%dL", col->atom_nb); break;
2324 case TFITS_BIN_TYPE_M: nb=sprintf(sval, "%dM",
2325 (int)(col->atom_nb/2)); break;
2326 case TFITS_BIN_TYPE_P: nb=sprintf(sval, "%dP",
2327 (int)(col->atom_nb/2)); break;
2328 case TFITS_BIN_TYPE_X: nb=sprintf(sval, "%dX",
2329 8*col->atom_nb); break;
2330 default: return NULL;
2331 }
2332 sval[nb] = '\0';
2333 return sval;
2334 }
2335
2336 /*----------------------------------------------------------------------------*/
2337 /**
2338 @brief Appends a std extension header + data to a FITS BIN table file.
2339 @param outfile Pointer to (opened) file ready for writing.
2340 @param t Pointer to qfits_table
2341 @param data Table data to write
2342 @return int 0 if Ok, -1 otherwise
2343
2344 Dumps a FITS table to a file. The whole table described by qfits_table, and
2345 the data arrays contained in 'data' are dumped to the file. An extension
2346 header is produced with all keywords needed to describe the table, then the
2347 data is dumped to the file.
2348 The output is then padded to reach a multiple of 2880 bytes in size.
2349 Notice that no main header is produced, only the extension part.
2350 */
2351 /*----------------------------------------------------------------------------*/
qfits_table_append_bin_xtension(FILE * outfile,const qfits_table * t,const void ** data)2352 static int qfits_table_append_bin_xtension(
2353 FILE * outfile,
2354 const qfits_table * t,
2355 const void ** data)
2356 {
2357 qfits_header * fh;
2358
2359 if ((fh=qfits_table_ext_header_default(t)) == NULL) {
2360 qfits_error("cannot create new fits header");
2361 return -1;
2362 }
2363
2364 /* Write the fits header in the file */
2365 if (qfits_header_dump(fh, outfile) == -1) {
2366 qfits_error("cannot dump header in file");
2367 qfits_header_destroy(fh);
2368 fclose(outfile);
2369 return -1;
2370 }
2371 qfits_header_destroy(fh);
2372
2373 /* Append the data to the file */
2374 return qfits_table_append_data(outfile, t, data);
2375 }
2376
2377 /*----------------------------------------------------------------------------*/
2378 /**
2379 @brief Appends an extension header + data to a FITS ASCII table file.
2380 @param outfile Pointer to (opened) file ready for writing.
2381 @param t Pointer to qfits_table
2382 @param data Table data to write
2383 @return int 0 if Ok, -1 otherwise
2384
2385 Dumps a FITS table to a file. The whole table described by
2386 qfits_table, and the data arrays contained in 'data' are dumped to
2387 the file. An extension header is produced with all keywords needed
2388 to describe the table, then the data is dumped to the file.
2389
2390 The output is then padded to reach a multiple of 2880 bytes in size.
2391
2392 Notice that no main header is produced, only the extension part.
2393 */
2394 /*----------------------------------------------------------------------------*/
qfits_table_append_ascii_xtension(FILE * outfile,const qfits_table * t,const void ** data)2395 static int qfits_table_append_ascii_xtension(
2396 FILE * outfile,
2397 const qfits_table * t,
2398 const void ** data)
2399 {
2400 qfits_header * fh;
2401
2402 if ((fh=qfits_table_ext_header_default(t)) == NULL) {
2403 qfits_error("cannot create new fits header");
2404 return -1;
2405 }
2406
2407 /* Write the fits header in the file */
2408 if (qfits_header_dump(fh, outfile) == -1) {
2409 qfits_error("cannot dump header in file");
2410 qfits_header_destroy(fh);
2411 return -1;
2412 }
2413 qfits_header_destroy(fh);
2414
2415 /* Append the data to the file */
2416 return qfits_table_append_data(outfile, t, data);
2417 }
2418
2419 /*----------------------------------------------------------------------------*/
2420 /**
2421 @brief Appends data to a FITS table file.
2422 @param outfile Pointer to (opened) file ready for writing.
2423 @param t Pointer to qfits_table
2424 @param data Table data to write
2425 @return int 0 if Ok, -1 otherwise
2426
2427 Dumps the data part of a FITS table to a file. The primary header, as well as
2428 the extension header are supposed to be already there (and properly padded).
2429 The output is then padded to reach a multiple of 2880 bytes in size.
2430 */
2431 /*----------------------------------------------------------------------------*/
qfits_table_append_data(FILE * outfile,const qfits_table * t,const void ** data)2432 static int qfits_table_append_data(
2433 FILE * outfile,
2434 const qfits_table * t,
2435 const void ** data)
2436 {
2437 qfits_col * curr_col;
2438 char field[1024];
2439 char * line;
2440 unsigned char ** array;
2441 unsigned char * r;
2442 unsigned char * inbuf;
2443 int writt_char;
2444 int nb_blanks;
2445 int field_size;
2446 int i, j;
2447
2448 /* Write DATA */
2449 array = qfits_malloc(t->nc*sizeof(unsigned char *));
2450
2451 curr_col = t->col;
2452 for (i=0; i<t->nc; i++) {
2453 /* Compute the field size */
2454 field_size = qfits_table_get_field_size(t->tab_t, curr_col);
2455
2456 /* Copy data from data to array (unsigned char) */
2457 array[i] = qfits_malloc(t->nr * field_size);
2458 r = (unsigned char *)array[i];
2459 inbuf = (unsigned char *)(data[i]);
2460
2461 /* Copy the data */
2462 if (t->tab_t == QFITS_ASCIITABLE) {
2463 /* ASCII table */
2464 for (j=0; j<t->nr; j++) {
2465 switch(curr_col->atom_type) {
2466 case TFITS_ASCII_TYPE_A :
2467 strncpy(field, (char*)inbuf, curr_col->atom_nb);
2468 field[curr_col->atom_nb] = '\0';
2469 inbuf += curr_col->atom_nb;
2470 break;
2471 case TFITS_ASCII_TYPE_D :
2472 memset(field, ' ', curr_col->atom_nb);
2473 sprintf(field, "%g", ((double*)data[i])[j]);
2474 field[curr_col->atom_nb] = '\0';
2475 break;
2476 case TFITS_ASCII_TYPE_E :
2477 case TFITS_ASCII_TYPE_F :
2478 memset(field, ' ', curr_col->atom_nb);
2479 sprintf(field, "%f", ((float*)data[i])[j]);
2480 field[curr_col->atom_nb] = '\0';
2481 break;
2482 case TFITS_ASCII_TYPE_I :
2483 memset(field, ' ', curr_col->atom_nb);
2484 sprintf(field, "%d", ((int*)data[i])[j]);
2485 field[curr_col->atom_nb] = '\0';
2486 break;
2487 default:
2488 break;
2489 }
2490 memcpy(r, field, curr_col->atom_nb);
2491 r += (curr_col->atom_nb);
2492 }
2493 } else if (t->tab_t == QFITS_BINTABLE) {
2494 /* BINARY table */
2495 for (j=0; j<t->nr; j++) {
2496 memcpy(r, inbuf, field_size);
2497 inbuf += field_size;
2498 r += field_size;
2499 }
2500
2501 /* Byte swapping needed if on a little-endian machine */
2502 #ifndef WORDS_BIGENDIAN
2503 if (curr_col->atom_size > 1) {
2504 r = array[i];
2505 for (j=0; j<t->nr * curr_col->atom_nb; j++) {
2506 qfits_swap_bytes(r, curr_col->atom_size);
2507 r += curr_col->atom_size;
2508 }
2509 }
2510 #endif
2511 } else return -1;
2512 curr_col++;
2513 }
2514
2515 /* Write to the outfile */
2516 writt_char = 0;
2517 for (i=0; i<t->nr; i++) {
2518 curr_col = t->col;
2519 for (j=0; j<t->nc; j++) {
2520 field_size = qfits_table_get_field_size(t->tab_t, curr_col);
2521 r = array[j] + field_size * i;
2522 line = (char *)qfits_calloc (field_size+1, sizeof (char));
2523 memcpy(line, r, field_size);
2524 line[field_size] = '\0';
2525 fwrite(line, 1, field_size, outfile);
2526 writt_char += field_size;
2527 curr_col++;
2528 qfits_free(line);
2529 }
2530 }
2531
2532 /* Complete with blanks to FITS_BLOCK_SIZE characters */
2533 if (writt_char % FITS_BLOCK_SIZE) {
2534 nb_blanks = FITS_BLOCK_SIZE - (writt_char%FITS_BLOCK_SIZE);
2535 for (i=1; i<=nb_blanks; i++) fwrite(" ", 1, 1, outfile);
2536 }
2537
2538 /* Free and return */
2539 for(i=0; i<t->nc; i++) {
2540 if (array[i] != NULL) qfits_free(array[i]);
2541 }
2542 qfits_free(array);
2543 return 0;
2544 }
2545
2546 /*----------------------------------------------------------------------------*/
2547 /**
2548 @brief Get the size in bytes of a field
2549 @param type table type
2550 @param col a column
2551 @return the size
2552 */
2553 /*----------------------------------------------------------------------------*/
qfits_table_get_field_size(int type,const qfits_col * col)2554 static int qfits_table_get_field_size(
2555 int type,
2556 const qfits_col * col)
2557 {
2558 int field_size;
2559
2560 switch (type) {
2561 case QFITS_BINTABLE:
2562 field_size = col->atom_nb * col->atom_size;
2563 break;
2564 case QFITS_ASCIITABLE:
2565 field_size = col->atom_nb;
2566 break;
2567 default:
2568 qfits_warning("unrecognized table type");
2569 field_size = -1;
2570 }
2571 return field_size;
2572 }
2573